Що не так з API дати та часу Java? [зачинено]


105

Дуже часто натрапляю на негативні відгуки про Java Dateта інші класи, пов’язані з датою та часом. Будучи розробником .NET, я не можу повністю (без їх використання) зрозуміти, що з ними насправді не так.

Чи може хтось пролити на це світло?


Відповіді:


142

Ах, Dateклас Java . Мабуть, один із найкращих прикладів того, як не робити чогось будь-якою мовою, ніде. З чого я починаю?

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

Однак дизайнерські рішення справді марнують будь-яку думку про те, що це добре розроблений API. Ось деякі з улюблених помилок:

  • Незважаючи на те, що він був розроблений в останнє десятиліття тисячоліття, він вважає роки двома цифрами з 1900 року. У світі Яви буквально мільйони обхідних завдань, які роблять 1900+ (або 1900-) років, в результаті цього банального рішення.
  • Місяці індексуються нулем, щоб задовольнити надзвичайно незвичайний випадок, що має масив місяців і не живе з тринадцятьма елементами масиву, перший з яких містить a null. Як результат, ми маємо 0..11 (і сьогодні це місяць 11 року 109). Існує аналогічна кількість ++ і - по місяцях для перетворення в рядок.
  • Вони змінюються . Як результат, у будь-який час, коли ви хочете повернути дату (скажімо, як структуру примірника), вам потрібно повернути клон цієї дати замість самого об’єкта дати (оскільки в іншому випадку люди можуть мутувати вашу структуру).
  • Створений Calendar, щоб "виправити" це, насправді робить ті самі помилки. Вони все ще змінюються.
  • Dateявляє собою DateTime, але для того, щоб відкласти їх до землі SQL, є ще один підклас java.sql.Date, який представляє один день (хоча без часового поясу, пов'язаного з ним).
  • Немає TimeZones, пов'язаних з a Date, і тому діапазони (наприклад, "цілий день") часто представлені як півночі-півночі (часто в будь-якому довільному часовому поясі)

Нарешті, варто відзначити, що високосні секунди, як правило, виправляються проти хорошого системного годинника, який оновлюється ntp протягом години (див. Посилання нижче). Шанс того, що система все ще працює і працює за впровадження двох високосних секунд (практично кожні півроку, практично кожні кілька років), є малоймовірною, особливо якщо врахувати той факт, що вам доведеться час від часу переробляти нові версії коду. . Навіть використання динамічної мови, яка відновлює класи або щось на кшталт двигуна WAR, забруднить простір класів і з часом вичерпається пермген.


43

JSR 310 , який витіснив старі класи дат-часу на java.time в Java 8, виправдовує себе в початковому JSR наступним чином:

2.5 Які потреби спільноти Java будуть вирішені запропонованою специфікацією?

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

Одна класична помилка (4639407) не дозволила створити певні дати в об’єкті Calendar. Можна записати послідовність коду, який міг би створити дату в деякі роки, а не в інші, що призведе до того, що деякі користувачі не зможуть ввести правильні дати народження. Це було спричинене тим, що клас «Календар» дозволяв лише літній час влітку збільшити час на годину, коли історично це було 2 години в часі другої світової війни. Незважаючи на те, що ця помилка тепер виправлена, якби в якийсь момент майбутнього країна вирішила впровадити літній час збільшення літнього часу плюс три години, тоді клас Календаря знову буде порушений.

Поточний Java SE API також страждає у багатопотокових середовищах. Як відомо, класи, що непорушні, по суті є безпечними для потоків, оскільки їх стан не може змінитися. Однак і Дата, і Календар змінні, що вимагає від програмістів чітко розглянути питання про клонування та введення тексту. Крім того, відсутність безпеки потоку в DateTimeFormat широко не відома, і це стало причиною багатьох важких проблем з винищенням потоків.

Як і проблеми з класами, які має Java SE на дату, у нього немає класів для моделювання інших понять. Дати або час без часових поясів, тривалість, періоди та інтервали не мають представлення класів у 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 - це також хороша зовнішня бібліотека, але апаш здається більш "загальним", ніж будь-що інше ...


Будь-ласка, покажіть нам, як це зробити ("дізнайтеся, скільки часу минуло між двома побаченнями")!
Антон Гоголєв

Я б хотів, щоб я знав простий шлях ... включаючи високосні роки, стрибаючі місяці та мінливі дні ...
Еран Медан

1
Дивіться також, org.apache.commons.lang.time
trashgod

@AntonGogolev У java.time використовуйте Periodта Durationкласи для обчислення та відображення минулого часу відповідно до шкали років-місяців-днів та годин-хвилин-секунд відповідно.
Василь Бурк

4

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

Joda Time - це добре відомий альтернативний API на Java, і в розділі «Час часу Joda» він дає ще кілька аргументів, чому це життєздатна альтернатива, яка може представляти інтерес.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.