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

364

Может кто-нибудь, пожалуйста, посоветуйте текущую «лучшую практику» вокруг Dateи наберите Calendar.

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

Марти Питт
источник
28
Время Joda: joda-time.sourceforge.net
Р. Мартиньо Фернандес
2
FYI, хлопотно старые классы даты и времени , такие как java.util.Date, java.util.Calendarи java.text.SimpleDateFormatтеперь наследие, вытесняется java.time классов. Большая часть функциональности java.time перенесена на Java 6 и Java 7 в проекте ThreeTen-Backport . Далее адаптирован для более ранней версии Android в проекте ThreeTenABP . Смотрите Как использовать ThreeTenABP… .
Василий Бурк
2
К вашему сведению, проект Joda-Time (упомянутый в другом комментарии) в настоящее время находится в режиме обслуживания , и команда советует перейти на классы java.time . Смотрите Учебник по Oracle .
Василий Бурк

Ответы:

377

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

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

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

Клетус
источник
5
К вашему сведению, ужасно неприятные старые классы даты и времени, такие как java.util.Date, java.util.Calendarи java.text.SimpleDateFormatтеперь унаследованные , вытеснены классами java.time, встроенными в Java 8 и более поздние версии . Смотрите Учебник по Oracle .
Базилик Бурк
67

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

И Date, и Calendar , имеют так много проблем проектирования, что ни один не является хорошим решением для нового кода.

dmeister
источник
7
Я второе предложение использовать время йода. Это проще в использовании и понимании и предлагает гораздо больше функциональных возможностей, которые вы можете использовать.
Йерун ван Берген
30
Для обсуждения следует ли использовать Joda время или палку со стандартными классами JDK см stackoverflow.com/questions/589870/...
Jonik
3
Я не знаю, заслуживает ли это отрицательных голосов, но это не отвечает на вопрос. Может быть просто лучше, как комментарий.
IcedDante
7
Потому что вопрос был в том, чтобы использовать Date и Calendar, а не стороннюю библиотеку, которая добавляет риск зависимости одного поставщика в проект.
Архимед Траяно
3
Это был «лучший способ» до тех пор, пока пакет java.time не стал доступен с Java 8.
DaBlick
58
  • Dateи Calendarна самом деле это одна и та же фундаментальная концепция (обе представляют момент времени и являются обертками вокруг основной longценности).

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

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

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

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

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

oxbow_lakes
источник
1
Есть ли временные рамки для JSR310? Это должно было быть в Java 7, но я считаю, что сейчас это не так.
Брайан Агнью
@ Брайан - в этом списке рассылки все прошло очень тихо!
oxbow_lakes
Просто проверил, что он неактивен, что означает, что они не опубликовали черновой вариант в течение 18 месяцев :-(
Брайан Агнью
Самый последний комментарий к списку рассылки относится к июлю и Стивену, так что проект, вероятно, все еще уходит
oxbow_lakes
Согласовано. Если вы знаете, как безопасно использовать Date в качестве неизменяемого объекта и Calendar для манипулирования датами, большинство людей должны быть в безопасности. Будьте осторожны при использовании SimpleDateFormat в многопоточном коде.
Cwash
25

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

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

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

KLE
источник
Я так понимаю, вы принимаете о неизменномjava.lang.Long
пдп
17

Я обычно использую Дата, если это возможно. Хотя это изменчиво, мутаторы фактически устарели. В конце это в основном оборачивает 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);
Архимед Траяно
источник
Да, неизменные объекты имеют смысл для работы с датой и временем. В java.time классы , которые вытеснили Date/ Calendarиспользовать неизменный шаблон объектов.
Базилик Бурк
Это может быть правдой, но не в 2010 году.
Архимед Траяно
Да. Но есть тысячи людей , читающих эту страницу в настоящее время , более чем 150000 до сих пор. Мой комментарий для них - заметка, а не критика.
Василий Бурк
Я знаю, поэтому я проголосовал против другого ответа. Тем не менее, есть еще люди, которым нужно страдать от старых JDK, которым тоже нужен ответ выше.
Архимед Траяно
1
На самом деле, для Java 6 & 7 у нас есть проект ThreeTen-Backport . Это обеспечивает большую часть функциональности java.time с практически одинаковым API. Поэтому нет необходимости когда-либо использовать эти ужасные устаревшие классы даты и времени.
Базилик Бурк
15

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

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

Анджей Дойл
источник
Да, неизменные объекты имеют смысл для работы с датой и временем. В java.time классы , которые вытеснили Date/ Calendarиспользовать неизменный шаблон объектов. В частности, Instantзаменяет java.util.Dateи ZonedDateTimeзаменяет Calendar/ GregorianCalendar.
Базилик Бурк
15

ТЛ; др

посоветуйте текущую «лучшую практику» DateиCalendar

это лучше , чтобы всегда благоприятствует CalendarнадDate

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

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

Таблица всех типов даты и времени в Java, как современных, так и устаревших

подробности

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

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

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

Для получения дополнительной информации о преобразовании см. Мой ответ и изящную диаграмму в другой вопрос. Преобразовать 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

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

Таблица какой библиотеки java.time использовать с какой версией Java или Android

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

Базилик Бурк
источник
10

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

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

Вы можете создать ZonedDateTimeобъект из старого java.util.Dateобъекта следующим образом:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
Ортомала Локни
источник
Хорошо предложить классы java.time. Но плохо предлагать LocalDateTime. Этот класс намеренно теряет любую информацию о смещении от UTC и часовом поясе. Так что этот класс не эквивалентен, как Dateв UTC, и Calendarимеет назначенный часовой пояс. Посмотрите мой ответ и отличную диаграмму на другой вопрос, конвертируйте java.util.Date в какой тип «java.time»? ,
Василий Бурк
9

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

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

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

Брайан Агнью
источник
3
В последний раз, когда я смотрел, JODA и JSR-310 выглядели очень по- разному, даже если они оба написаны Стивеном Коулборном. Тем не менее, JODA познакомит вас со сложностью проблем с датой и временем, которые JSR-310 также решает
oxbow_lakes
2
Потому что вопрос был в том, чтобы использовать Date и Calendar, а не стороннюю библиотеку, которая добавляет риск зависимости одного поставщика в проект.
Архимед Траяно
2
Я утверждаю, что лучшая практика просто не использовать эти классы
Брайан Агнью
3
Учитывая известные проблемы с классами java.util.Date и Calendar, предложение Joda-Time (или JSR 310) кажется мне подходящим и ответственным. Мы не говорим о вкусе или эстетическом стиле. Если кто-то спросил, стоит ли им брать красную машину или серебристую машину, и я знал, что у красной машины спущенная шина, а у серебряной машины - сломанный радиатор, мне следует выбрать машину или предложить вызвать такси? Ответ на этот вопрос в наши дни должен казаться очевидным, так как даже Sun / Oracle решили оставить позади этих юнкеров и купить новый автомобиль: JSR 310: API даты и времени.
Василий Бурк
1
К вашему сведению, проект Joda-Time сейчас находится в режиме обслуживания , рекомендуя переход на классы java.time . Смотрите Учебник по Oracle .
Базилик Бурк
8

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

Сильвиу Бурча
источник
1

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

В нашем естественном разговоре, если назначить встречу на 1 ноября 2013 г. 13:00 по Нью-Йоркскому времени, это DateTime. Это НЕ Календарь. Таким образом, мы должны иметь возможность общаться и в Java.

Когда Дата хранится в виде длинного целого числа (в миллионах секунд с 1 января 1970 года или около того), вычисление текущей даты зависит от календаря. Разные календари будут давать разные даты. Это с точки зрения предоставления абсолютного времени (например, 1 триллион секунд после Большого взрыва). Но часто нам также нужен удобный способ общения, например, год, месяц и т. Д.

Интересно, есть ли новые достижения в Java для согласования этих двух целей. Может быть, мои знания Java слишком стары.

user2835562
источник
Тот факт, что вы можете хранить один и тот же момент времени, но сообщать о разных часах / минутах / днях / неделях / годах / фу на основе разных календарных систем, - это сила, а не слабость. Это отражает (сложную) реальность.
ThrawnCA
Действительно, Dateбыл переработан; заменить на java.time.Instantкласс. И Calendar/ GregorianCalendarбыл заменен на java.time.ZonedDateTimeкласс.
Базилик Бурк
0

Кстати, «дата» обычно помечается как «устаревшая / устаревшая» (я точно не знаю, почему) - там что-то написано об этом Java: почему конструктор Date устарел и что вместо этого использовать?

Похоже, что это проблема конструктора только через новую дату (int year, int month, int day) , рекомендуемый путь - через Calendar и задает параметры отдельно .. ( Calendar cal = Calendar.getInstance (); )

xxxvodnikxxx
источник
0

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

Брайан Нельсон
источник
FYI, хлопотно Calendarи Dateклассы были вытеснены лет назад java.time классов. Нет необходимости когда-либо использовать Dateили Calendar. И не Localeимеет ничего общего со значениями объектов даты и времени. A Localeиспользуется только для указания человеческого языка и культурных норм, которые будут использоваться при локализации при создании текста для представления значения объекта даты и времени.
Базилик Бурк