Дата Java проти календаря


364

Невже хтось може порадити поточну "найкращу практику" навколо DateтаCalendar типів.

При написанні нового коду, це краще , щоб завжди сприяє Calendarбільш Date, або там , де обставина Dateє більш відповідним типом даних?



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
FYI, проект Joda-Time (згаданий в іншому коментарі) зараз перебуває в режимі обслуговування , і команда радить перейти до класів java.time . Дивіться Підручник від Oracle .
Василь Бурк

Відповіді:


377

Дата - це простіший клас, і в основному він існує з міркувань відсталої сумісності. Якщо вам потрібно встановити конкретні дати або зробити арифметику дат, використовуйте Календар. Календарі також обробляють локалізацію. Функції маніпуляції з попередньою датою з тих пір застаріли.

Особисто я схильний використовувати або час у мілісекундах як довгий (або Довгий, якщо потрібно) або Календар, коли є вибір.

І Дата, і Календар змінні, що має тенденцію представляти проблеми при використанні будь-якого в API.


5
FYI, жахливі старі класи дату, такі як java.util.Date, java.util.Calendarі java.text.SimpleDateFormatтепер застарілі , витіснені класами java.time, вбудованими в Java 8 та новіших версій. Дивіться Підручник від Oracle .
Василь Бурк

67

Найкращий спосіб нового коду (якщо ваша політика дозволяє сторонній код) - використовувати бібліотеку часу Joda .

І в " Дата", і в " Календарі" є стільки проблем із дизайном, що не є хорошими рішеннями для нового коду.


7
Я друге пропозиція використовувати час joda. Він простіший у використанні та розумінні та пропонує набагато більше функціональних можливостей, які ви можете використовувати.
Йероен ван Берген

30
Щоб обговорити, чи використовувати Joda Time або дотримуватися стандартних класів JDK, дивіться stackoverflow.com/questions/589870/…
Jonik

3
Я не знаю, чи заслуговує вона на низових місцях, але це не відповідає на питання. Може бути просто краще, як коментар.
IcedDante

7
Оскільки питання стосувалося використання дати та календаря, а не використання бібліотеки сторонніх розробників, що додає проект ризику залежності від одного постачальника.
Архімед Траяно

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 ) дійсно настільки складні для більшості випадків використання.


1
Чи є часові рамки для JSR310? Це було б у Java 7, але я вважаю, що зараз це не так.
Брайан Агнеу

@Brian - це звичайно дуже спокійно в цьому списку розсилки!
oxbow_lakes

Тільки перевіряючи, що вона втратила неактивність, а це означає, що вони не опублікували черговий етап за 18 місяців :-(
Брайан Агнеу

Останній коментар до списку розсилки - з липня та Стівена, тому проект, ймовірно, ще
відмічається

Домовились. Якщо ви знаєте, як безпечно використовувати Date, як незмінний об’єкт, і Календар для маніпулювання датами, більшість людей повинні бути в безпеці. Будьте обережні, використовуючи SimpleDateFormat у багатопотоковому коді.
cwash

25

Дата найкраща для зберігання об’єкта дати. Це збережений, серіалізований ...

Календар найкращий для маніпулювання датами.

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


Я вважаю, що ви ставитесь до незмінногоjava.lang.Long
pjp

17

Я, як правило, використовую Date, якщо можливо. Хоча це мутація, мутатори насправді застаріли. Зрештою, він в основному обгортає довгий, який би представляв дату / час. І навпаки, я використовував би календарі, якщо мені доведеться маніпулювати значеннями.

Ви можете подумати про це так: StringBuffer ви використовуєте лише тоді, коли вам потрібно мати рядки, якими ви можете легко маніпулювати, а потім перетворювати їх у Strings за допомогою методу 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 слід використовувати як незмінні моменти в часі; Calendars є змінними, і їх можна передавати та змінювати, якщо вам потрібно співпрацювати з іншими класами, щоб визначити кінцеву дату. Розглянемо їх аналогічно StringтаStringBuilder , і ви зрозумієте , як я вважаю , що вони повинні бути використані.

(І так, я знаю, що Дата насправді не є технічно незмінною, але наміром є те, що вона не повинна бути зміною, і якщо нічого не викликає застарілі методи, то це так.)


Так, незмінні об'єкти мають сенс для роботи з датою та часом. У 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 - це величезне вдосконалення в порівнянні зі застарілими класами дати та часу, різниця в ніч і день. Старі класи погано розроблені, заплутані та клопітні. Ви повинні уникати старих класів, коли це можливо. Але коли вам потрібно перетворити на / зі старого / нового, ви можете це зробити, викликаючи нові методи додати до старих класів.

Більше інформації про конверсію див. У моїй схемі відповідей та вишуканості на інше запитання: Перетворити java.util.Дати тип "java.time"?.

Пошук переповнення стека дає багато сотень прикладів запитань та відповідей щодо використання java.time. Але ось швидкий конспект.

Instant

Отримайте поточний момент за допомогою Instant. InstantКлас являє собою момент на шкалі часу в форматі UTC з дозволом наносекунд (до дев'яти (9) цифр десяткового дробу).

Instant instant = Instant.now();

ZonedDateTime

Побачити той самий момент, що пройшов крізь лінзу настінного годинника певного регіону , застосуйте часовий пояс ( ZoneId), щоб отримати а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 . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація є 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… .

Таблиця, яку бібліотеку 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.Зверніть на тип "java.time"? .
Василь Бурк

9

Я завжди виступаю за Joda-час . Ось чому.

  1. API послідовний та інтуїтивно зрозумілий. На відміну від API java.util.Date/Calendar
  2. вона не страждає від проблем з нанизуванням, на відміну від java.text.SimpleDateFormat тощо (я бачив численні проблеми клієнта, які стосуються того, що не розумію, що стандартне форматування дати / часу не є безпечним для потоків)
  3. це основа нових API дати / часу Java ( JSR310 , запланованих на Java 8. Отже, ви будете використовувати API, які стануть основними API Java.

EDIT: Класи дати / часу Java, введені з Java 8, тепер є кращим рішенням, якщо ви можете перейти на Java 8


3
Востаннє, коли я дивився, JODA та JSR-310 виглядали дуже по- різному, навіть якщо їх обох написав Стівен Колбурн. З цього приводу JODA познайомить вас зі складністю проблем, що вирішуються на дату, які також вирішує JSR-310
oxbow_lakes

2
Оскільки питання стосувалося використання дати та календаря, а не використання бібліотеки сторонніх розробників, що додає проект ризику залежності від одного постачальника.
Архімед Траяно

2
Я вважаю, що найкраща практика - просто не використовувати ці заняття
Брайан Агнеу

3
Враховуючи відомі проблеми з класами java.util.Date та Calendar, я вважаю, що Joda-Time (або JSR 310) здається мені підходящим і відповідальним. Ми не говоримо про питання смаку чи естетичного стилю. Якщо хтось запитав, чи варто брати червону машину чи срібну машину, і я знав, що у червоного автомобіля є плоска шина, а у срібної машини є розбитий радіатор, я повинен вибрати машину чи мені запропонувати викликати таксі? Відповідь на це питання сьогодні може здатися очевидною, оскільки навіть Sun / Oracle вирішили залишити позаду цих юнкерів і придбати нову машину: JSR 310: API API дати та часу.
Василь Бурк

1
FYI, проект Joda-Time зараз перебуває в режимі обслуговування , радить переходити до класів java.time . Дивіться Підручник від Oracle .
Василь Бурк

8

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


1

Дату слід переробити. Замість того, щоб бути довгим інтергером, він повинен містити рік, місяць, дату, годину, хвилину, секунду, як окремі поля. Можливо, навіть буде добре зберігати календар і часовий пояс, з якими пов’язана ця дата.

У нашій природній розмові, якщо призначити зустріч на 1 листопада 2013 р. 13:00 NY, це датаTime. Це НЕ календар. Таким чином, ми повинні мати можливість подібного спілкування і в Java.

Коли Дата зберігається як довге ціле число (мільйонних секунд з 1 січня 1970 року або щось таке), обчислення його поточної дати залежить від календаря. Різні календарі дадуть різну дату. Це пов'язано з перспективою надання абсолютного часу (наприклад, 1 трлн секунд після Великого вибуху). Але часто нам також потрібен зручний спосіб розмови, як об'єкт, що інкапсулює рік, місяць тощо.

Цікаво, чи є нові досягнення в Яві для досягнення цих двох цілей. Можливо, мої знання про Java занадто давні.


Те, що ви можете зберігати одну і ту ж мить у часі, але повідомляти про різну годину / хвилину / день / тиждень / рік / коло на основі різних календарних систем, є силою, а не слабкістю. Він відображає (складну) реальність.
ThrawnCA

Дійсно, Dateбув перероблений; замінено java.time.Instantкласом. І Calendar/ GregorianCalendarбув замінений java.time.ZonedDateTimeкласом.
Василь Бурк

0

Btw "дата" зазвичай позначена як "застаріла / застаріла" (я точно не знаю чому) - щось про це написано там Java: Чому конструктор дат застарів, і що я використовую замість цього?

Схоже, це проблема конструктора лише через нову дату (int рік, int місяць, int день) , рекомендований спосіб - через Календар і встановлюйте параметри окремо .. ( Calendar cal = Calendar.getInstance (); )


0

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


FYI, клопітніCalendar та Dateкласи були витіснені років тому класами java.time . Ніколи не потрібно використовувати Dateабо Calendar. І не Localeмає нічого спільного зі значеннями об'єктів дати та часу. A Localeвикористовується лише для визначення людської мови та культурних норм, які слід використовувати при локалізації під час створення тексту для відображення значення об'єкта дати та часу.
Василь Бурк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.