Использование GregorianCalendar с SimpleDateFormat

Так что я ломал голову над этим (должно быть) простым упражнением, чтобы заставить программу превратить строку даты в объект GregorianCalendar, отформатировать ее и вернуть снова в виде строки, когда это будет сделано.

Это последняя небольшая часть программы, которая берет фрагмент текста из файла, разбивает его на отдельные записи, затем разбивает записи на отдельные фрагменты данных и присваивает их объекту person.

Я проверил код в нескольких местах, и код делает именно то, что должен делать до тех пор, пока я не вызову функцию форматирования, которая вызывает исключение IllegalArgumentException. Объекту GergorianCalendar назначают значения, которые он должен назначить (хотя печать это, опять же, совершенно другая история, как показано ниже...), но формат не будет принимать объект для форматирования.

К сожалению, инструктор не был слишком уверен в том, как использовать GregorianCalendar и SimpleDateFormat (но поручил нам работать с ними), и сказал: "Просто Google это"... Я пытался, и ничего, что я нашел, не помогло.

Код, который у меня пока есть:

public class DateUtil {

    public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{

        // this actually works, got rid of the original code idea
        String[] splitDate = dd_mm_yy.split("-");
        int days = Integer.parseInt(splitDate[0]);
        int month = Integer.parseInt(splitDate[1]);
        int year = Integer.parseInt(splitDate[2]);

        // dates are going in right, checked in print statement,
        // but the object is not getting formatted...
        GregorianCalendar dateConverted = new GregorianCalendar(year, month, days);
        format(dateConverted);
        return dateConverted;
    }

    public static String format(GregorianCalendar date){

        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
        String dateFormatted = fmt.format(date);
        return dateFormatted;
    }
}

Я получаю ошибку:

Исключение в потоке "main" java.lang.IllegalArgumentException: не удается отформатировать данный объект> как дату

    в java.text.DateFormat.format(DateFormat.java:281)
    в java.text.Format.format(Format.java:140)
    at lab2.DateUtil.format(DateUtil.java:26) 
    at lab2.DateUtil.convertFromDMY(DateUtil.java:19)
    в lab2.Lab2.createStudent(Lab2.java:75)
    в lab2.Lab2.main(Lab2.java:34)

И еще, я даже использую право GregorianCalendar?? Когда я распечатываю значение этого объекта (должна быть дата правильно?), Я получаю это:

java.util.GregorianCalendar [время =?,areFieldsSet= ложь,areAllFieldsSet= ложь, мягко = верно, зона =sun.util.calendar.ZoneInfo[ID = "Америка / Ванкувер", смещение =-28800000,dstSavings=3600000,useDaylight= верно, переходы =189,lastRule=java.util.SimpleTimeZone[ID = Америка / Ванкувер, смещение =-28800000,dstSavings=3600000,useDaylight= верно, StartYear=0, StartMode=3, StartMonth=2,startDay=8,startDayOfWeek=1, =7200000 начальный промежуток,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1, EndTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1, ЭРА =?, ГОД =1985, МЕСЯЦ =4,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=22, day_of_year =?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0, ЧАС =0,HOUR_OF_DAY=0, МИНУТНЫЙ = 0, = ВТОРАЯ 0, миллисекунды =?,ZONE_OFFSET=?,DST_OFFSET=?]

Значения year, month и day_of_month являются правильными, поскольку они являются числами, которые я передал при его создании.

Мысли, предложения, я даже близко?

редактировать

исходные проблемы устранены (спасибо, ассилий!), но я все еще не могу печатать должным образом, потому что две функции не связаны, и необходимо, чтобы значение даты GregorianCalendar было распечатано из объекта person (поскольку дата рождения - это GregorianCalendar).

Обновленный код:

public class DateUtil {

    static SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");

    public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{

        // this actually works, got rid of the original code idea
        String[] splitDate = dd_mm_yy.split("-");
        int days = Integer.parseInt(splitDate[0]);
        int month = (Integer.parseInt(splitDate[1]) - 1);
        int year = Integer.parseInt(splitDate[2]);

        // dates go in properly
        GregorianCalendar dateConverted = new GregorianCalendar(year, month, days);
        String finalDate = format(dateConverted);
        return ;
    }

    public static String format(GregorianCalendar date) throws ParseException{

       fmt.setCalendar(date);
        String dateFormatted = fmt.format(date.getTime());
        System.out.println(dateFormatted);
        return dateFormatted;
    }

}

последнее редактирование

Итак, кажется, что я идиот, и мне не нужно связывать две функции DateUtil вместе, но используйте их в тандеме. Сначала преобразуйте дату рождения в GregorianCalendar и сохраните ее в объекте person. Затем в заявлении на печать просто скажите программе отформатировать эту дату по мере ее печати. Проблема была решена. Теперь все работает в соответствии со спецификациями, и я чувствую себя намного глупее, потому что в последний день или около того с классом DateUtil я летал, как рыба, из воды, пытаясь заставить их работать одновременно.

Спасибо всем за помощь в получении даты, чтобы войти правильно!

5 ответов

Решение

SimpleDateFormat#format метод занимает Date в качестве параметра. Вы можете получить Date из Calendar позвонив его getTime метод:

public static String format(GregorianCalendar calendar){
    SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
    fmt.setCalendar(calendar);
    String dateFormatted = fmt.format(calendar.getTime());
    return dateFormatted;
}

Также обратите внимание, что месяцы начинаются с 0, так что вы, вероятно, имели в виду:

int month = Integer.parseInt(splitDate[1]) - 1;

Почему такие осложнения?

public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException 
{
    SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
    Date date = fmt.parse(dd_mm_yy);
    GregorianCalendar cal = GregorianCalendar.getInstance();
    cal.setTime(date);
    return cal;
}

SimpleDateFormat, как указывает его название, форматирует даты. Не календарь. Поэтому, если вы хотите отформатировать GregorianCalendar с использованием SimpleDateFormat, вы должны сначала преобразовать календарь в дату:

dateFormat.format(calendar.getTime());

И то, что вы видите напечатанным, является представлением календаря toString(). Предполагаемое использование - отладка. Он не предназначен для отображения даты в графическом интерфейсе. Для этого используйте (простой)DateFormat.

Наконец, чтобы преобразовать строку в дату, вы должны также использовать (простой)DateFormat (его parse() метод), а не разделять строку, как вы делаете. Это даст вам объект Date, и вы можете создать календарь из Date, создав его экземпляр (Calendar.getInstance()) и установка его времени (calendar.setTime()).

Мой совет: поиск в Google не является решением проблемы. Чтение документации по API - это то, что вам нужно сделать.

ТЛ; др

LocalDate.parse(
    "23-Mar-2017" ,
    DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US ) 
)

Избегайте устаревших классов даты и времени

Вопрос и другие ответы теперь устарели, и в них использовались старые классы даты и времени, которые были устаревшими и вытеснены классами java.time.

Использование java.time

Вы, кажется, имеете дело со значениями только для даты. Так что не используйте класс даты-времени. Вместо этого используйте LocalDate, LocalDate класс представляет значение только для даты без времени суток и без часового пояса.

Укажите Locale определить (а) человеческий язык для перевода названия дня, названия месяца и т. д. и (б) культурных норм, решающих вопросы сокращения, использования заглавных букв, пунктуации, разделителей и т. д.

Разобрать строку.

String input = "23-Mar-2017" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US ) ;
LocalDate ld = LocalDate.parse( input , f );

Генерация строки.

String output = ld.format( f );

Если вам были даны цифры, а не текст года, месяца и дня месяца, используйте LocalDate.of,

LocalDate ld = LocalDate.of( 2017 , 3 , 23 );  // ( year , month 1-12 , day-of-month )

Смотрите этот код в прямом эфире на IdeOne.com.

вход: 23 марта 2017 года

ld.toString(): 2017-03-23

выходной: 23 марта 2017 года


О java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые классы даты и времени, такие как java.util.Date, Calendar & SimpleDateFormat,

Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.

Чтобы узнать больше, смотрите Oracle Tutorial. И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310.

Используя драйвер JDBC, совместимый с JDBC 4.2 или новее, вы можете обмениваться объектами java.time напрямую с вашей базой данных. Нет необходимости ни в строках, ни в классах java.sql.*.

Где взять классы java.time?

  • Java SE 8, Java SE 9 и более поздние
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
  • Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь, такие как Interval, YearWeek, YearQuarter и многое другое.

  1. Вы помещаете туда двухзначный год. Первый век. И григорианский календарь начался в 16 веке. Я думаю, вы должны добавить 2000 к году.

  2. Месяц в функции new GregorianCalendar(год, месяц, дни) основан на 0. Вычтите 1 из месяца там.

  3. Измените тело второй функции так:

        String dateFormatted = null;
        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
        try {
            dateFormatted = fmt.format(date);
        }
        catch ( IllegalArgumentException e){
            System.out.println(e.getMessage());
        }
        return dateFormatted;
    

После отладки вы увидите, что просто GregorianCalendar не может быть аргументом fmt.format();

Действительно, GregorianCalendar никому не нужен в качестве вывода, даже если вам говорят, что нужно возвращать "строку".

Измените заголовок функции вашего формата на

public static String format(Date date) 

и внесите соответствующие изменения. fmt.format() с удовольствием возьму объект Date.

  1. Всегда, когда возникает неожиданное исключение, ловите его сами, не позволяйте java-машине делать это. Таким образом, вы поймете проблему.
Другие вопросы по тегам