Что не так с Java Date & Time API? [закрыто]

106

Очень часто я сталкиваюсь с отрицательными отзывами о Java Dateи других классах, связанных с датой и временем. Как .NET-разработчик, я не могу полностью (без их использования) понять, что с ними на самом деле не так.

Кто-нибудь может пролить свет на это?

Антон Гоголев
источник

Ответы:

142

Ах, Dateкласс Java . Пожалуй, один из лучших примеров того, как что-то не делать на любом языке и нигде. С чего бы мне начать?

Читая JavaDoc, можно подумать, что у разработчиков действительно есть несколько хороших идей. Подробно говорится о разнице между UTC и GMT , несмотря на то, что разница между ними в основном составляет високосные секунды (что случается довольно редко ).

Однако дизайнерские решения действительно сводят на нет любую мысль о том, чтобы быть хорошо разработанным API. Вот некоторые из любимых ошибок:

  • Несмотря на то, что он был разработан в последнее десятилетие тысячелетия, он оценивает годы как две цифры с 1900 года. В мире Java существуют буквально миллионы обходных путей, которые делают 1900+ (или 1900-) в результате этого банального решения.
  • Месяцы имеют нулевую индексацию, чтобы удовлетворить чрезвычайно необычный случай наличия массива месяцев и отсутствия массива из тринадцати элементов, первый из которых содержит null. В результате имеем 0..11 (а сегодня 11 месяц 109 года). В месяцах используется аналогичное количество ++ и - для преобразования в строку.
  • Они изменчивы . В результате каждый раз, когда вы хотите вернуть дату (например, как структуру экземпляра), вам нужно вернуть клон этой даты вместо самого объекта даты (поскольку в противном случае люди могут изменить вашу структуру).
  • Разработанный Calendar, чтобы «исправить» это, на самом деле совершает те же ошибки. Они все еще изменчивы.
  • Dateпредставляет собой DateTime, но для того, чтобы отложить это до тех, кто работает в области SQL, существует другой подкласс java.sql.Date, который представляет один день (хотя и без связанного с ним часового пояса).
  • Нет TimeZones, связанных с a Date, поэтому диапазоны (например, `` целый день '') часто представлены как полночь-полночь (часто в некотором произвольном часовом поясе)

Наконец, стоит отметить, что дополнительные секунды обычно корректируются относительно хороших системных часов, которые обновляются с помощью ntp в течение часа (см. Ссылки ниже). Вероятность того, что система все еще будет запущена и будет работать после введения двух дополнительных секунд (минимум каждые шесть месяцев, практически каждые несколько лет), весьма маловероятна, особенно с учетом того факта, что вам придется время от времени повторно развертывать новые версии вашего кода. . Даже использование динамического языка, который регенерирует классы или что-то вроде механизма WAR, приведет к загрязнению пространства классов и в конечном итоге исчерпает permgen.

AlBlue
источник
43

JSR 310 , который заменил старые классы даты и времени на java.time в Java 8, оправдывает себя в исходной JSR следующим образом:

2.5 Какие потребности сообщества Java будут удовлетворены предлагаемой спецификацией?

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

Одна классическая ошибка (4639407) препятствовала созданию определенных дат в объекте Calendar. Можно написать последовательность кода, которая могла бы создать дату в одни годы, но не в другие, что помешало бы некоторым пользователям вводить правильные даты рождения. Это было вызвано тем, что класс Calendar позволял переходить на летнее время только на один час летом, тогда как исторически это было плюс 2 часа во время Второй мировой войны. Хотя эта ошибка сейчас исправлена, если в какой-то момент в будущем страна решит ввести увеличение летнего времени плюс три часа летом, тогда класс Calendar снова будет сломан.

Текущий API Java SE также страдает в многопоточных средах. Неизменяемые классы по своей сути являются потокобезопасными, поскольку их состояние не может измениться. Однако и Date, и Calendar являются изменяемыми, что требует от программистов явного рассмотрения клонирования и потоковой передачи. Кроме того, недостаточная безопасность потоков в DateTimeFormat широко не известна и является причиной многих трудных для отслеживания проблем с потоками.

Помимо проблем с классами, которые Java SE имеет для datetime, в нем нет классов для моделирования других концепций. Даты или время, не относящиеся к часовому поясу, длительности, периоды и интервалы не имеют представления класса в Java SE. В результате разработчики часто используют int для обозначения продолжительности времени, а javadoc указывает единицу.

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

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

меритон
источник
28
  • Экземпляры даты изменяемы , что почти всегда неудобно.
  • У них двоякая природа. Они представляют собой метку времени и календарную дату. Оказывается, это проблематично при расчетах по датам.
  • Числовое представление данных календаря во многих случаях противоречит интуиции. Например: getMonth()отсчитывается от нуля, getYear()отсчитывается от 1900 (т. Е. 2009 год представлен как 109).
  • Им не хватает многих функций, которые вы ожидаете от Dateкласса.
свиристель
источник
13

Я сочувствую вам ... как бывший .NET-программист, я задавал те же вопросы, API времени в .NET (временные интервалы, перегрузка операторов) очень удобен.

Во-первых, чтобы создать конкретную дату, вы используете либо устаревший API, либо:

Calendar c = Calendar.getInstance();
c.set(2000, 31, 12)

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

Date firstDate = ...
Calendar c = Calendar.getInstance();
c.setTime(fistDate);
c.add(Calendar.DATE,-1);
Date dayAgo = c.getTime();

или хуже

Date d = new Date();
Date d2 = new Date(d.getTime() - 1000*60*60*24);

Чтобы узнать, сколько времени прошло между двумя датами (в днях / неделях / месяцах) ... становится еще хуже

Однако DateUtils из apache ( org.apache.commons.lang.time.DateUtils) предлагает несколько удобных методов, и в последнее время я использовал только их.

Как писал Брабстер, Joda Time также является хорошей внешней библиотекой, но apache кажется более "распространенным", чем что-либо еще ...

Эран Медан
источник
Пожалуйста, покажите нам, как это сделать («узнайте, сколько времени прошло между двумя свиданиями»)!
Антон Гоголев
Хотел бы я знать легкий путь ... включая високосные годы, беспокойные месяцы и нестабильные дни ...
Эран Медан
1
См. Также org.apache.commons.lang.time: commons.apache.org/lang//api/org/apache/commons/lang/time/…
trashgod
@AntonGogolev В java.time , использование Periodи Durationклассы для расчета и представления истекшее время по шкале лет-месяцев дни и часы-минуты-секунды соответственно.
Базиль Бурк,
4

Честно говоря, я считаю, что Java Date API можно использовать. Большинство вопросов , которые я видел и слышал о связанно с многословием, необходимость вовлечения нескольких классов , чтобы сделать что - нибудь полезное ( Calendar, Date, DateFormat/ SimpleDateFormat) и отсутствие простых аксессоров как getDayOfWeek().

Joda Time - это хорошо зарекомендовавший себя альтернативный API на Java, и в разделе «Почему Joda Time» приводится еще несколько аргументов в пользу того, почему это жизнеспособная альтернатива, которая может представлять интерес.

хвастун
источник