Java Дата против Календарь - PullRequest
       70

Java Дата против Календарь

350 голосов
/ 10 сентября 2009

Может ли кто-нибудь посоветовать текущую "наилучшую практику" по типам Date и Calendar.

При написании нового кода лучше всегда отдавать предпочтение Calendar над Date, или есть обстоятельства, когда Date является более подходящим типом данных?

Ответы [ 13 ]

369 голосов
/ 10 сентября 2009

Дата является более простым классом и в основном используется для обеспечения обратной совместимости. Если вам нужно установить конкретные даты или сделать арифметику дат, используйте календарь. Календари также обрабатывают локализацию. Предыдущие функции манипуляции с датой Date с тех пор устарели.

Лично я склонен использовать либо время в миллисекундах как long (или Long, в зависимости от ситуации), так и Calendar, когда есть выбор.

И Дата, и Календарь являются изменяемыми, что приводит к проблемам при использовании любого из них в API.

66 голосов
/ 10 сентября 2009

Лучший способ для нового кода (если ваша политика допускает использование стороннего кода) - это использовать библиотеку Joda Time .

Оба, Дата и Календарь , имеют столько проблем с дизайном, что ни одно из них не является хорошим решением для нового кода.

55 голосов
/ 10 сентября 2009
  • Date и Calendar на самом деле являются одной и той же фундаментальной концепцией (оба представляют момент времени и являются обертками вокруг базового значения long).

  • Можно утверждать, что Calendar на самом деле даже более сломлен, чем Date, поскольку, как представляется, он предлагает конкретные факты о таких вещах, как день недели и время суток, тогда как если вы измените свойство timeZone, бетон превратится в бланманже! По этой причине ни один объект не может быть полезен в качестве магазина год-месяц-день или время-день .

  • Используйте Calendar только в качестве калькулятора, который при задании объектов Date и TimeZone будет выполнять вычисления для вас. Избегайте его использования для ввода свойств в приложении.

  • Используйте SimpleDateFormat вместе с TimeZone и Date для генерации отображаемых строк.

  • Если вы чувствуете себя авантюрным, используйте Joda-Time, хотя это излишне сложное IMHO и вскоре в любом случае будет заменено API даты JSR-310.

  • Я уже отвечал ранее, что нетрудно создать свой собственный класс YearMonthDay, который использует Calendar под капотом для вычисления даты. Я был отвергнут за это предложение, но я все еще считаю его действительным, потому что Joda-Time JSR-310 ) действительно слишком сложны для большинства вариантов использования.

25 голосов
/ 10 сентября 2009

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

Календарь лучше всего подходит для манипулирования датами.

Примечание: мы также иногда предпочитаем java.lang.Long, а не Date, потому что Date является изменяемым и, следовательно, не поточно-ориентированным. В объекте Date используйте setTime () и getTime () для переключения между ними. Например, константа Date в приложении (примеры: ноль 1970/01/01 или аппликативный END_OF_TIME, для которого установлено значение 2099/12/31; это очень полезно для замены нулевых значений в качестве времени начала и окончания, особенно когда вы сохраняете их в базе данных, так как SQL свойственен нулям).

17 голосов
/ 15 июня 2010

Обычно я использую дату, если это возможно. Хотя это изменчиво, мутаторы фактически устарели. В конце это в основном оборачивает long, который будет представлять дату / время. И наоборот, я бы использовал календари, если бы мне пришлось манипулировать значениями.

Вы можете думать об этом так: вы используете StringBuffer только тогда, когда вам нужны строки, которыми вы можете легко манипулировать, а затем конвертировать их в строки с помощью метода toString (). Таким же образом я использую Календарь только если мне нужно манипулировать временными данными.

Для лучшей практики я стараюсь использовать как можно больше неизменных объектов вне доменной модели . Это значительно снижает вероятность возникновения любых побочных эффектов и выполняется для вас компилятором, а не тестом JUnit. Вы используете эту технику, создавая частные окончательные поля в вашем классе.

И возвращаясь к аналогии с StringBuffer. Вот некоторый код, который показывает вам, как конвертировать между Календарем и Датой

String s = "someString"; // immutable string
StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer
buf.append("x");
assertEquals("someStringx", buf.toString()); // convert to immutable String

// immutable date with hard coded format.  If you are hard
// coding the format, best practice is to hard code the locale
// of the format string, otherwise people in some parts of Europe
// are going to be mad at you.
Date date =     new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02");

// Convert Date to a Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);

// mutate the value
cal.add(Calendar.YEAR, 1);

// convert back to Date
Date newDate = cal.getTime();

// 
assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);
15 голосов
/ 10 сентября 2009

Date s следует использовать как неизменные моменты времени; Calendar являются изменяемыми и могут быть переданы и изменены, если вам нужно сотрудничать с другими классами, чтобы придумать окончательную дату. Считайте их аналогичными String и StringBuilder, и вы поймете, как я считаю, их следует использовать.

(И да, я знаю, что Date фактически не является технически неизменным, но предполагается, что она не должна быть изменяемой, и если ничто не вызывает устаревшие методы, то это так.)

11 голосов
/ 28 февраля 2017

ТЛ; др

рекомендует текущую "лучшую практику" около Date и Calendar

лучше всегда отдавать предпочтение Calendar более Date

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

  • На мгновение в UTC , используйте Instant
    (современный эквивалент Date)
  • На мгновение в конкретном часовом поясе используйте ZonedDateTime
    (современный эквивалент GregorianCalendar)
  • На мгновение в конкретном смещении от UTC , используйте OffsetDateTime
    (нет эквивалента в унаследованных классах)
  • Для даты-времени (не момента) с неизвестным часовым поясом или смещением используйте LocalDateTime
    (нет эквивалента в унаследованных классах)

Подробнее

Ответ от Ortomala Локни вправе предложить использовать современные java.time классы, а не трудоемкие старые классы даты и времени (Date, Calendar, так далее.). Но в этом ответе предлагается неправильный класс как эквивалентный (см. Мой комментарий к этому ответу).

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

Классы java.time - это огромное улучшение по сравнению с традиционными классами даты и времени, разница между днем ​​и ночью. Старые классы плохо спроектированы, запутаны и хлопотны. Вы должны избегать старых классов, когда это возможно. Но когда вам нужно преобразовать в / из старого / нового, вы можете сделать это, вызвав новые методы, добавляемые к old классам.

Для получения дополнительной информации о преобразовании см. мой ответ и изящную диаграмму в другой вопрос, Преобразовать java.util.Date для какого типа «java.time»? .

Поиск переполнения стека дает сотни примеров вопросов и ответов по использованию java.time. Но вот краткий обзор.

Instant

Получить текущий момент с Instant. Класс Instant представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).

Instant instant = Instant.now();

ZonedDateTime

Чтобы увидеть, что тот же самый одновременный момент через линзу времени настенных часов некоторого конкретного региона , примените часовой пояс (ZoneId), чтобы получить a ZonedDateTime.

Часовой пояс

Укажите собственное имя часового пояса в формате continent/region, например America/Montreal, Africa/Casablanca или Pacific/Auckland. Никогда не используйте 3-4-буквенное сокращение, такое как EST или IST, поскольку они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();

Смещение

Часовой пояс - это история изменений региона в его смещении от UTC . Но иногда вам дают только смещение без полной зоны. В этом случае используйте класс OffsetDateTime.

ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );

Использование часового пояса предпочтительнее использования простого смещения.

LocalDateTime

«Локальный» в классах Local… означает любой населенный пункт, а не конкретный населенный пункт. Так что имя может быть нелогичным.

LocalDateTime, LocalDate и LocalTime преднамеренно не содержат никакой информации о смещении или часовом поясе. Таким образом, они не представляют фактические моменты, они не точек на временной шкале. В случае сомнений или путаницы используйте ZonedDateTime вместо LocalDateTime. Поиск переполнения стека для гораздо большего обсуждения.

Строка

Не путайте объекты даты и времени со строками, представляющими их значение. Вы можете проанализировать строку, чтобы получить объект даты и времени, и вы можете сгенерировать строку из объекта даты и времени. Но строка никогда не является самой датой-временем.

Узнайте о стандартных ISO 8601 форматах, используемых по умолчанию в классах java.time.


О java.time

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

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

Чтобы узнать больше, см. Учебное пособие по Oracle . И поиск переполнения стека для многих примеров и объяснений. Спецификация 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
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android проект ThreeTenABP адаптируется ThreeTen-Backport (упоминалось выше). См. Как использовать ThreeTenABP… .

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

10 голосов
/ 15 июня 2015

В Java 8 следует использовать новый java.time пакет .

Объекты неизменны, учитываются часовые пояса и экономия дневного света.

Вы можете создать ZonedDateTime объект из старого java.util.Date объекта, подобного этому:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
9 голосов
/ 10 сентября 2009

Я всегда защищаю Йода-тайм . Вот почему.

  1. API является последовательным и интуитивно понятным. В отличие от API java.util.Date/Calendar
  2. он не страдает от проблем с многопоточностью, в отличие от java.text.SimpleDateFormat и т. Д. (Я видел множество проблем с клиентом, связанных с непониманием того, что стандартное форматирование даты / времени не поточно-ориентировано ) * +1010 *
  3. это основа новых API даты / времени Java ( JSR310 , запланированных для Java 8. Поэтому вы будете использовать API, которые станут основными API Java.

РЕДАКТИРОВАТЬ: Java-классы даты / времени, представленные в Java 8, теперь являются предпочтительным решением, если вы можете перейти на Java 8

8 голосов
/ 23 мая 2014

Немного опоздал на вечеринку, но в Java есть новый API Date Time в JDK 8. Возможно, вы захотите обновить версию JDK и принять стандарт. Нет больше грязной даты / календаря, больше нет банок сторонних производителей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...