Что не так с Java Date & Time API?

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

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

5 ответов

Решение

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

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

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

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

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

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 будет решать проблему полной модели даты и времени, включая дату и время (с часовыми поясами и без них), длительности и периоды времени, интервалы, форматирование и анализ.

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

Я чувствую к вам... как бывший программист.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 кажется более "обычным", чем все остальное...

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

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

Другие вопросы по тегам