2010-01-30 3 views
24

Что является лучшей практикой для управления и хранения дат, например. используя GregorianCalendar в корпоративном Java-приложении?Какова наилучшая практика для управления и хранения дат в Java?

Ищет обратную связь, и я объединю любые большие ответы в Лучшую Практику, которую другие могут использовать. Благодаря!

+7

bla bla bla, joda time, bla bla bla ... –

ответ

12

Joda - это путь. Зачем ?

  1. он имеет гораздо более мощных и интуитивно понятный интерфейс, чем стандартный Date/Time API
  2. нет никаких проблем с пронизывающими датами/время форматирования. java.text.SimpleDateFormat не поточно-(не много людей знают это!)

На каком-то этапе Java Date/Time API собирается быть заменен (по JSR-310). Я считаю, что это будет основано на работе, проделанной теми, кто стоит за Джодой, и таким образом вы будете изучать API, который будет влиять на новый стандартный Java API.

+0

Теперь, если вы не можете использовать Joda (некоторые проекты ограничены в том, какие внешние JAR, которые они могут представить в проекте), использует java.util.GregorianCalendar для хранения и управления датами (убедитесь, что вы учитываете DST, делая что-то вроде поддержания ваши даты в часовой пояс UTC) лучшая практика? – BestPractices

+0

FYI, проект [Joda-Time] (http://www.joda.org/joda-time/) теперь находится в режиме обслуживания, а команда советует перейти на [java.time] (http: // docs .oracle.com/javase/8/docs/api/java/time/package-summary.html). –

+0

Действительно? Я не знал этого. Thx для головок вверх –

-2

Чтобы получить обсуждение начался, здесь был мой опыт:

При создании стандартов для типичного 3-уровневого проекта Java Enterprise, я обычно рекомендую проект использовать GregorianCalendar для управления датами. Причина: GregorianCalendar является стандартом де-факто над любым другим экземпляром календаря, например. Юлианский календарь и т. Д. Это признанный календарь в большинстве стран и правильно обрабатывает високосные годы и т. Д. Кроме того, я бы рекомендовал, чтобы приложение хранили свои даты в формате UTC, чтобы вы могли легко выполнять вычисления даты, например, находить разницу между двумя даты (если он был сохранен как EST, например, вам нужно было учитывать дневное свечение). Дата может быть локализована в любой часовой пояс, в котором вы нуждаетесь, чтобы она отображалась пользователю, например, как локализация ее в EST, если вы являетесь компанией США на восточном побережье, и вам нужна информация о времени, указанная в EST.

+3

«Например, юлианский календарь и т. Д.» Это можно оставить, поскольку это не имеет никакого смысла. Слишком много угловых случаев, чтобы начать перечислять вещи здесь. Например, астрономы используют номер астрономического юлианского дня. Они также используют григорианские даты. Лучше сказать меньше об этом. Кроме того, он помогает использовать пули для каждой из ваших точек. –

+1

Почему трехуровневый проект отличается от любого другого проекта? – jontejj

+0

FYI, старые классы времени-времени, такие как ['java.util.Date'] (https://docs.oracle.com/javase/8/docs/api/java/util/Date.html), [' java.util.Calendar'] (https://docs.oracle.com/javase/8/docs/api/java/util/Date.html), а 'java.text.SimpleTextFormat' теперь [legacy] (https : //en.wikipedia.org/wiki/Legacy_system), вытесненный [java.time] (https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html). –

10

Joda time (100% совместимость с JDK)

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

+0

FYI, проект [Joda-Time] (http://www.joda.org/joda-time/) теперь находится в режиме обслуживания, а команда советует перейти на [java.time] (http: // docs .oracle.com/javase/8/docs/api/java/time/package-summary.html). –

25

Лучшей практикой является, как правило, НЕ думать в терминах объектов с тяжелой датой, но хранить точку во времени. Обычно это делается путем хранения значения, которое не страдает от угловых случаев или от возможных проблем синтаксического анализа. Для этого люди обычно сохраняют количество миллисекунд (или секунд), прошедшее с момента фиксированной точки, которую мы называем эпохой (1970-01-01). Это очень распространено, и любой Java API всегда позволит вам конвертировать любую дату в/из времени, выраженного в ms с эпохи.

Это для хранения. Вы также можете сохранить, например, предпочтительный часовой пояс пользователя, если есть такая необходимость.

Теперь такая дата в миллисекундах, как:

System.out.println(System.currentTimeMillis()); 
1264875453 

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

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

Вы попросили передовую практику, вот мое взятие на себя: хранение объектов «даты» в БД вместо времени в миллисекундах прямо там с использованием чисел с плавающей запятой для представления денежных сумм.

Это, как правило, огромный запах кода.

Итак, время Джоды в Java - это способ манипулирования датой, да. Но есть ли Джода путь к магазин даты? НЕКОТОК.

2

UTC

Think, работа, и хранить данные в UTC, а не любой часовой пояс. Подумайте о UTC как One True Time, а все остальные часовые пояса - это просто варианты. Поэтому, кодируя, забудьте все о своем часовом поясе. Сделайте свою бизнес-логику, протоколирование, хранение данных и обмен данными в UTC. Я предлагаю, чтобы каждый программист держал на часах часы, установленные на UTC.

java.time

Современный способ является java.time классы.

Проект Joda-Time предоставил вдохновение для классов java.time, и проект теперь находится в режиме обслуживания с командой, предлагающей переход на классы java.time.

Рамка java.time встроена в Java 8 и более поздних версий. Эти классы вытесняют неприятные старые legacy классы времени, такие как java.util.Date, .Calendar, & java.text.SimpleDateFormat.

Чтобы узнать больше, см. Oracle Tutorial. И поиск Stack Overflow для многих примеров и объяснений. Спецификация: JSR 310.

Где получить классы java.time?

  • Java SE 8 и SE 9, а затем
    • Встроенный.
    • Часть стандартного Java API с объединенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time будет обратно портирован на Java 6 & 7 в ThreeTen-Backport.
  • Android
    • Проект ThreeTenABP адаптирует ThreeTen-Backport (как упоминалось выше) для Android специально.
    • См. How to use….

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

ISO 8601

При сериализации значение даты и времени в текст, использовать стандарт ISO 8601.

Например, время в UTC: 2016-10-17T01:24:35Z Адрес Z Номер модели: Zulu и означает UTC. Для других offset-from-UTC в конце появляется смещение часов и минут, например 2016-01-23T12:34:56+05:30. Классы java.time расширяют этот стандартный формат, чтобы добавить имя часового пояса (если известно) в квадратных скобках, например 2016-01-23T12:34:56+05:30[Asia/Kolkata].

Стандарт имеет множество других удобных форматов, а также в том числе для durations, intervals, ordinals и year-week.

Database

Для хранения баз данных, использование типов даты и времени для значений даты и времени, например, SQL standard data types которые в первую очередь DATE, TIME и TIMESTAMP WITH TIME ZONE.

Позвольте вашему JDBC driver сделать тяжелый подъем. Драйвер обрабатывает подробные сведения о посредничестве и адаптации между внутренними системами того, как Java обрабатывает данные и как ваша база данных обрабатывает данные на своей стороне. Но обязательно ознакомьтесь с примерами данных, чтобы узнать поведение вашего драйвера и вашей базы данных. Стандарт SQL очень мало описывает обработку с датой и временем, поэтому поведение сильно различается, что удивительно.

Если вы используете драйвер JDBC, совместимый с JDBC 4.2 и более поздними версиями, вы можете напрямую загружать и хранить типы java.time с помощью методов ResultSet::getObject и PreparedStatement::setObject.

Instant instant = myResultSet.getObject(…); 
myPreparedStatement.setObject(… , instant); 

Для старых драйверов вам необходимо вернуться к преобразованию типов java.sql. Ищите новые методы преобразования, добавленные в старые классы. Например, java.sql.Timestamp.toInstant().

Instant instant = myResultSet.getTimestamp(…).toInstant(); 
myPreparedStatement.setObject(… , java.sql.Timestamp.from(instant)); 

Используйте типы java.sql как можно короче. Они плохо обработаны, например, java.sql.Date, маскируясь как значение только для даты, но на самом деле в качестве подкласса java.util.Date оно действительно имеет время, установленное для 00:00:00 в UTC. И, о, вы должны игнорировать факт того, что наследование говорит класс doc. Уродливый беспорядок.

Пример кода

Получить текущий момент в UTC.

Instant instant = Instant.now(); 

Сохранение и извлечение, что Instant объект/из базы данных показано выше.

Чтобы создать строку ISO 8601, просто вызовите toString. Ява.во всех классах по умолчанию используются форматы ISO 8601 по умолчанию для синтаксического анализа и генерации строк их различных значений даты и времени.

String output = instant.toString(); 

Adjust в любой офсетной из-UTC с применением ZoneOffset, чтобы получить OffsetDateTime. Вызовите toString для создания строки в формате ISO 8601.

ZoneOffset offset = ZoneOffset.ofHoursMinutes(5 , 30); 
OffsetDateTime odt = instant.atOffset(offset); 

Временной зона является смещением плюса набором правил для обработки аномалий, таких как Daylight Saving Time (DST). Когда вам нужно увидеть тот же самый момент через объектив своего региона wall-clock time, примените часовой пояс (ZoneId), чтобы получить объект ZonedDateTime.

Укажите proper time zone name в формате continent/region. Никогда не используйте аббревиатуру 3-4 буквы, такую ​​как EST или IST, поскольку они не являются настоящими часовыми поясами, а не стандартизированы и даже не уникальны (!).

ZoneId z = ZoneId.of("Asia/Kolkata"); 
ZonedDateTime zdt = instant.atZone(z); 

Переход в другую сторону, вы можете извлечь Instant из OffsetDateTime или ZonedDateTime по телефону toInstant.

Instant instant = zdt.toInstant(); 

Форматирование

Для представления пользователю в виде строк в отличных от ISO 8601, search Stack Overflow для использования DateTimeFormatter класса форматов.

Пока вы можете указать нестандартный формат, обычно лучше всего разрешить java.time автоматически локализовать. Чтобы локализовать, укажите:

  • FormatStyle, чтобы определить, насколько длинной или сокращенной должна быть строка.
  • Locale определить (а) человеческий язык для перевода имени дня, названия месяца и т. Д. И (b) культурных норм, решающих вопросы сокращения, капитализации, пунктуации и т. Д.

Пример:

Locale l = Locale.CANADA_FRENCH ; 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(l); 
String output = zdt.format(f); 

Конверсия

Лучше всего, чтобы избежать типов даты и времени унаследованных всякий раз, когда это возможно. Но если вы работаете со старым кодом, который еще не обновлен для типов java.time, вы можете конвертировать в/из типов java.time. Подробнее см. В Вопросе, Convert java.util.Date to what “java.time” type?.

Использование объектов

Использование объектов, а не простые закодированных примитивов и простых строк. Например:

  • Не использовать 1-7, чтобы представить день-неделю, используйте DayOfWeek перечисление таких как DayOfWeek.TUESDAY.
  • Вместо того чтобы проходить вокруг строки в качестве даты, пройдите около LocalDate объектов.
  • Вместо того чтобы проходить пару целых чисел за год и месяц, пройдите около YearMonth объектов.
  • Вместо 1-12 в течение месяца используйте гораздо более читаемый список Month, такой как Month.JANUARY.

Использование таких объектов делает ваш код более самодокументированным, обеспечивает достоверные значения и предоставляет type-safety.

Смежные вопросы