Рекомендуемое использование для Joda-Time DateMidnight
javdoc для LocalDate#toDateMidnight
читается следующим образом:
Начиная с версии 1.5, рекомендуется избегать DateMidnight и использовать toDateTimeAtStartOfDay() вместо этого из-за подробного исключения ниже.
Этот метод генерирует исключение, если переключатели часовых поясов по умолчанию на летнее время в полночь, и это LocalDate представляет эта дата переключения. Проблема в том, что нет такого времени, как полночь в требуемую дату, и как таковое исключение.
Тот факт, что полночь не существует в определенных часовых поясах, кажется достаточной для того, чтобы избежать использования DateMidnight
целиком (при условии, что ваш код не использует фиксированный часовой пояс, который, как известно, не имеет такой ситуации летнего времени, и ему никогда не понадобится использовать различные часовые пояса в будущем).
Однако DateMidnight
не устарел, и в javadoc для класса DateMidnight
нет аналогичной рекомендации или предупреждения. Более того, конструктор DateMidnight
счастливо принимает мгновенный и часовой пояс таким образом, что полночь не существует в данный день, а не бросает IllegalArgumentException
как LocalDate#toDateMidnight
. Результирующий DateMidnight
ведет себя как a DateTime
со временем в начале дня.
Когда полночь не существует в данный день, почему LocalDate#toDateMidnight
выдает исключение, а конструктор DateMidnight
не работает? Каков рекомендуемый прецедент для DateMidnight
, если таковой имеется?
Ответы
Ответ 1
Нет веских оснований для использования DateMidnight
. LocalDate
- лучший вариант. Это потому, что полночь не возникает раз в год в определенных часовых поясах, полностью испортив удобство использования класса и создавая ошибки в приложениях.
Конструктор был исправлен, чтобы избежать наихудшей проблемы, однако просмотр объекта DateMidnight
с внутренним миллисекундным значением, указывающим в 01:00, не очень велик.
Ответ 2
new DateTime(). withTimeAtStartOfDay().
Ответ 3
Или лучше использовать метод LocalDate
toDateTimeAtStartOfDay
напрямую, чтобы обойти создание объекта DateTime
(относительно ответить выше).
new LocalDate().toDateTimeAtStartOfDay( myDateTimeZone )
Ответ 4
TL;DR
Используйте java.time классы, в частности LocalDate::atStartOfDay
вместо скользкой идеи о "полночь".
ZoneId z = ZoneId.of( "America/Montreal" ); // A time zone.
ZonedDateTime todayStart = LocalDate.now( z ).atStartOfDay( z ); // Produces a LocalDate (a whole day without time zone), then transforms into a `ZonedDateTime` (a moment on the timeline)
java.time
Поскольку проект Joda-Time теперь находится в режиме обслуживания, и команда советует перейти на классы java.time, я добавлю пример с помощью java.time.
Если вы хотите представить весь день в целом, используйте класс LocalDate
. Класс LocalDate
представляет значение даты только без времени и без часового пояса.
A часовой пояс имеет решающее значение для определения даты. В любой данный момент дата изменяется по всему миру по зонам. Например, через несколько минут после полуночи в Париж Франция - это новый день, пока еще "вчера" в Монреаль Квебек.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
Как обсуждалось на этой странице, попытка определить конец дня - это плохая практика. Во-первых, у вас есть проблема бесконечно делимой фракции за последнюю вторую часть дня. Вы решаете миллисекунды, микросекунды, наносекунды или что-то еще, так как все они широко используются? Вместо этого используйте первый момент нового дня.
Пусть java.time определяет время настенных часов этого первого момента дня. Не предполагайте, что время будет 00:00:00
, поскольку аномалии, такие как переход на летнее время (DST), могут означать, что первым моментом является время, например 01:00:00
. Такие корректировки DST в настоящее время используются во временных зонах нескольких стран.
Итак, чтобы получить мгновение, фактическая точка на временной шкале, для начала дня вызовите LocalDate::atStartOfDay
. Обратите внимание, что это более короткая версия имени метода, чем используется в методе Joda-Times withTimeAtStartOfDay
. Укажите желаемый/ожидаемый часовой пояс в ZoneId
, чтобы создать объект ZonedDateTime
.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = today.atStartOfDay( z );
Half-Open
Итак, как представить промежуток времени? Если я хочу точно определить начало и конец этого единственного дня, как мне это сделать, а также следовать этому совету? Решение, обычно используемое в работе с датой, - это подход Half-Open. В этом подходе начало диапазона включается, в то время как окончание является исключительным. Поэтому "сегодня" означает начать с первого момента дня и проделать весь путь до первого, но не включая, первого момента следующего дня.
ZonedDateTime zdtStartToday = LocalDate.now( z ).atStartOfDay( z );
ZonedDateTime zdtStartTomorrow = zdtStartToday.plusDays( 1 );
Кстати, проект ThreeTen-Extra имеет удобный Interval
для таких промежутков времени.
Interval todayInterval = Interval.of(
zdtStartToday.toInstant() ,
zdtStartTomorrow.toInstant()
)
О java.time
Структура java.time встроена в Java 8 и более поздних версий. Эти классы вытесняют неприятные старые классы времени, такие как java.util.Date
, .Calendar
и java.text.SimpleDateFormat
.
Проект Joda-Time, теперь режим обслуживания, советует перейти на java.time.
Чтобы узнать больше, см. Учебник Oracle. И поиск Qaru для многих примеров и объяснений.
Большая часть функциональных возможностей java.time портирована на Java 6 и 7 в ThreeTen-Backport и далее адаптирована к Android в ThreeTenABP (см. Как использовать...).
Проект ThreeTen-Extra расширяет java.time с дополнительными классами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval
, YearWeek
, YearQuarter
и больше.
Ответ 5
Посмотрите на исключение, которое я имел в своем коде
Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-27T00:00:00.000 (Asia/Amman)
org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-27T00:00:00.000 (Asia/Amman)
Теперь я решил это, используя
LocalDate currentDate=new LocalDate();
someMethodSetsTheDate(currentDate.toDateTimeAtStartOfDay().toDate());
Вместо
someMethodSetsTheDate(new DateMidnight(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth()).toDate());
Теперь моя рекомендация - использовать
.toDateTimeAtStartOfDay()
чтобы избежать подобных исключений.
Пожалуйста, не стесняйтесь редактировать мой ответ Спасибо