Java: почему конструктор Date устарел и что вместо него использовать? - PullRequest
190 голосов
/ 15 апреля 2011

Я из мира C #, поэтому еще не слишком разбираюсь в Java.Eclipse только что сказал, что Date устарело:

Person p = new Person();
p.setDateOfBirth(new Date(1985, 1, 1));

Почему?И что (особенно в случаях, подобных описанным выше) следует использовать вместо этого?

Ответы [ 12 ]

230 голосов
/ 15 апреля 2011

Класс java.util.Date на самом деле не рекомендуется, просто этот конструктор вместе с парой других конструкторов / методов устарел.Это устарело, потому что такое использование плохо работает с интернационализацией.Вместо этого следует использовать класс Calendar:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1988);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
Date dateRepresentation = cal.getTime();

Взгляните на дату Javadoc:

http://download.oracle.com/javase/6/docs/api/java/util/Date.html

93 голосов
/ 15 апреля 2011

Определенный Date конструктор устарел, и вместо него следует использовать Calendar. JavaDoc для Дата описывает, какие конструкторы устарели и как их заменить, используя Calendar.

64 голосов
/ 06 февраля 2014

ТЛ; др

LocalDate.of( 1985 , 1 , 1 )

... или ...

LocalDate.of( 1985 , Month.JANUARY , 1 )

Детали

Классы java.util.Date, java.util.Calendar и java.text.SimpleDateFormat были запущены слишком быстро при первом запуске и развитии Java. Классы не были хорошо разработаны или реализованы. Попытки улучшения были предприняты, таким образом, найденные вами амортизации. К сожалению, попытки улучшения в основном не увенчались успехом. Вы должны избегать этих классов в целом. Они вытесняются в Java 8 новыми классами.

Проблемы в вашем коде

java.util.Date содержит как дату, так и часть времени. Вы проигнорировали часть времени в своем коде. Таким образом, класс Date будет принимать начало дня в соответствии с часовым поясом JVM по умолчанию и применять это время к объекту Date. Таким образом, результаты вашего кода будут различаться в зависимости от того, на каком компьютере он работает или какой часовой пояс установлен. Наверное, не то, что вы хотите.

Если вам нужна только дата, без временной части, например, для даты рождения, вы можете не использовать объект Date. Вы можете сохранить только строку даты в формате ISO 8601 , равном YYYY-MM-DD. Или используйте объект LocalDate из Joda-Time (см. Ниже).

Joda-Time

Первое, чему нужно научиться на Java: Избегайте печально известных хлопотных классов java.util.Date & java.util.Calendar в комплекте с Java.

Как правильно отмечено в ответе user3277382 , используйте либо Joda-Time , либо новый java.time. * Пакет в Java 8.

Пример кода в Joda-Time 2.3

DateTimeZone timeZoneNorway = DateTimeZone.forID( "Europe/Oslo" );
DateTime birthDateTime_InNorway = new DateTime( 1985, 1, 1, 3, 2, 1, timeZoneNorway );

DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTime birthDateTime_InNewYork = birthDateTime_InNorway.toDateTime( timeZoneNewYork ); 

DateTime birthDateTime_UtcGmt = birthDateTime_InNorway.toDateTime( DateTimeZone.UTC );

LocalDate birthDate = new LocalDate( 1985, 1, 1 );

Дамп на консоль ...

System.out.println( "birthDateTime_InNorway: " + birthDateTime_InNorway );
System.out.println( "birthDateTime_InNewYork: " + birthDateTime_InNewYork );
System.out.println( "birthDateTime_UtcGmt: " + birthDateTime_UtcGmt );
System.out.println( "birthDate: " + birthDate );

При запуске ...

birthDateTime_InNorway: 1985-01-01T03:02:01.000+01:00
birthDateTime_InNewYork: 1984-12-31T21:02:01.000-05:00
birthDateTime_UtcGmt: 1985-01-01T02:02:01.000Z
birthDate: 1985-01-01

java.time

В этом случае код для java.time практически идентичен коду Joda-Time .

Мы получаем часовой пояс (ZoneId) и создаем объект даты и времени, назначенный этому часовому поясу (ZonedDateTime). Затем, используя шаблон Immutable Objects , мы создаем новые даты и даты, основанные на том же мгновении старого объекта (количество наносекунд с эпохи ), но назначенном другом часовом поясе. Наконец, мы получаем LocalDate, в котором нет ни времени суток, ни часового пояса, хотя обратите внимание, что часовой пояс применяется при определении этой даты (новый день наступает раньше в Осло , чем в Нью-Йорк например).

ZoneId zoneId_Norway = ZoneId.of( "Europe/Oslo" );
ZonedDateTime zdt_Norway = ZonedDateTime.of( 1985 , 1 , 1 , 3 , 2 , 1 , 0 , zoneId_Norway );

ZoneId zoneId_NewYork = ZonedId.of( "America/New_York" );
ZonedDateTime zdt_NewYork = zdt_Norway.withZoneSameInstant( zoneId_NewYork );

ZonedDateTime zdt_Utc = zdt_Norway.withZoneSameInstant( ZoneOffset.UTC );  // Or, next line is similar.
Instant instant = zdt_Norway.toInstant();  // Instant is always in UTC.

LocalDate localDate_Norway = zdt_Norway.toLocalDate();

О java.time

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

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

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

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

Где получить классы java.time?

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

11 голосов
/ 28 мая 2015

Я столкнулся с этим вопросом как с дубликатом более нового вопроса , в котором был задан вопрос о том, как получить неустрашимый способ получить Date в определенный год, месяц и день.

В приведенных здесь ответах говорится, что используется класс Calendar, и это было правдой до выхода Java 8.Но для Java 8 стандартный способ сделать это:

LocalDate localDate = LocalDate.of(1985, 1, 1);

И затем, если вам действительно нужен java.util.Date, вы можете использовать предложения из этого вопроса .

Для получения дополнительной информации, ознакомьтесь с API или учебными пособиями для Java 8.

11 голосов
/ 15 апреля 2011

Одна из причин, по которой конструктор устарел, заключается в том, что значение параметра year не соответствует ожидаемому.В Javadoc написано:

Начиная с версии 1.1 JDK, заменено на Calendar.set(year + 1900, month, date).

Обратите внимание, что поле year - это число лет с 1900, поэтомуваш пример кода, скорее всего, не будет делать то, что вы ожидаете.И в этом все дело.

В общем случае API Date поддерживает только современный западный календарь, имеет специфически определенные компоненты и ведет себя непоследовательно, если вы задаете поля.

Calendar иGregorianCalendar API лучше, чем Date, и сторонние Joda-time API, как правило, считались лучшими.В Java 8 они представили пакеты java.time, и теперь они являются рекомендуемой альтернативой.

8 голосов
/ 20 декабря 2013

Обратите внимание, что Calendar.getTime() является недетерминированным в том смысле, что часть дневное время по умолчанию принимает текущее время.

Чтобы воспроизвести, попробуйте выполнить следующий код пару раз:

Calendar c = Calendar.getInstance();
c.set(2010, 2, 7); // NB: 2 means March, not February!
System.err.println(c.getTime());

Вывод например ::1009*

Sun Mar 07 10:46:21 CET 2010

Выполнение точно такого же кода через пару минут приводит к:

Sun Mar 07 10:57:51 CET 2010

Итак, set() заставляет соответствующиеполя для исправления значений, он пропускает системное время для других полей.(Проверено выше с Sun jdk6 и jdk7)

6 голосов
/ 15 апреля 2011

Date само по себе не считается устаревшим. Это просто много его методов. Подробнее см. Здесь .

Вместо этого используйте java.util.Calendar.

5 голосов
/ 06 февраля 2014

Большинство разработчиков Java в настоящее время используют сторонний пакет Joda-Time .Это широко признано, чтобы быть намного лучшей реализацией.

Java 8 однако будет иметь новый java.time. * Пакет .См. Эту статью, Представление нового API даты и времени для JDK 8 .

1 голос
/ 11 июля 2018

Вы можете создать метод, подобный new Date(year,month,date) в своем коде, используя класс Calendar.

private Date getDate(int year,int month,int date){
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, year);
    cal.set(Calendar.MONTH, month-1);
    cal.set(Calendar.DAY_OF_MONTH, day);
    return cal.getTime();
}

Он будет работать так же, как устаревший конструктор Date

1 голос
/ 15 апреля 2011

Подобно тому, что предложил binnyb, вы можете использовать более новый метод Calendar> GregorianCalendar. Смотрите эти более свежие документы:

http://download.oracle.com/javase/6/docs/api/java/util/GregorianCalendar.html

...