ТЛ; др
LocalDate // Represents an entire day, without time-of-day and without time zone.
.now( // Capture the current date.
ZoneId.of( "Asia/Tokyo" ) // Returns a `ZoneId` object.
) // Returns a `LocalDate` object.
.atStartOfDay( // Determines the first moment of the day as seen on that date in that time zone. Not all days start at 00:00!
ZoneId.of( "Asia/Tokyo" )
) // Returns a `ZonedDateTime` object.
Начало дня
Получите полную длину сегодняшнего дня в часовом поясе.
Использование полуоткрытого подхода, когда начало включено, а окончание - эксклюзивно . Такой подход устраняет ошибку в вашем коде, которая не учитывает самую последнюю секунду дня.
ZoneId zoneId = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( zoneId ) ;
ZonedDateTime zdtStart = today.atStartOfDay( zoneId ) ;
ZonedDateTime zdtStop = today.plusDays( 1 ).atStartOfDay( zoneId ) ;
zdtStart.toString () = 2020-01-30T00: 00 + 01: 00 [Африка / Тунис]
zdtStop.toString () = 2020-01-31T00: 00 + 01: 00 [Африка / Тунис]
Смотрите те же моменты в UTC.
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
start.toString () = 2020-01-29T23: 00: 00Z
stop.toString () = 2020-01-30T23: 00: 00Z
Если вы хотите, чтобы весь день даты отображался в формате UTC, а не в часовом поясе, используйте OffsetDateTime
.
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
OffsetDateTime odtStart = today.atTime( OffsetTime.MIN ) ;
OffsetDateTime odtStop = today.plusDays( 1 ).atTime( OffsetTime.MIN ) ;
odtStart.toString () = 2020-01-30T00: 00 + 18: 00
odtStop.toString () = 2020-01-31T00: 00 + 18: 00
Эти OffsetDateTime
объекты уже будут в формате UTC, но вы можете позвонить, toInstant
если вам нужны такие объекты, которые по определению всегда находятся в формате UTC.
Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;
start.toString () = 2020-01-29T06: 00: 00Z
stop.toString () = 2020-01-30T06: 00: 00Z
Совет: вас может заинтересовать добавление библиотеки ThreeTen-Extra в ваш проект, чтобы использовать ее Interval
класс для представления этой пары Instant
объектов. Это обеспечивает класс полезные методы для сравнения , такие как abuts
, overlaps
, contains
и многое другое.
Interval interval = Interval.of( start , stop ) ;
interval.toString () = 2020-01-29T06: 00: 00Z / 2020-01-30T06: 00: 00Z
Полуоткрытый
Ответ на mprivat правильно. Его цель - не пытаться получить конец дня, а скорее сравнить с «до начала следующего дня». Его идея известна как «полуоткрытый» подход, в котором у отрезка времени есть начало, включающее, а окончание - исключительное .
- Текущие рамки времени и даты Java (java.util.Date/Calendar и Joda-Time ) оба используют миллисекунды от эпохи . Но в Java 8 новые классы JSR 310 java.time. * Используют разрешение наносекунды. Любой код, который вы написали, основанный на принудительном подсчете миллисекунд последнего момента дня, будет неправильным, если переключиться на новые классы.
- Сравнение данных из других источников становится некорректным, если они используют другие разрешения. Например, библиотеки Unix обычно используют целые секунды, а базы данных, такие как Postgres, преобразуют дату и время в микросекунды.
- Некоторые изменения летнего времени происходят за полночь, что может еще больше запутать ситуацию.
Joda-Time 2.3 предлагает метод для этой цели, чтобы получить первый момент дня: withTimeAtStartOfDay()
. Аналогично в java.time LocalDate::atStartOfDay
.
Поищите в StackOverflow «joda half-open», чтобы увидеть больше обсуждений и примеров.
См. Этот пост Билла Шнайдера « Временные интервалы и другие диапазоны должны быть полуоткрытыми ».
Избегайте устаревших классов даты и времени
Классы java.util.Date и .Calendar, как известно, проблематичны. Избежать их.
Используйте классы java.time . Java.time структура является официальным преемником весьма успешной Joda-Time библиотеки.
java.time
Фреймворк java.time встроен в Java 8 и новее. Обратно перенесен на Java 6 и 7 в проекте ThreeTen-Backport , а затем адаптирован для Android в проекте ThreeTenABP .
An Instant
- это момент на временной шкале в формате UTC с разрешением наносекунды .
Instant instant = Instant.now();
Примените часовой пояс, чтобы узнать время на настенных часах для некоторой местности.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Чтобы получить первое мгновение дня, просмотрите LocalDate
класс и его atStartOfDay
метод.
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
Используя подход Half-Open, получите первый момент следующего дня.
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
В настоящее время в структуре java.time отсутствует Interval
класс, описанный ниже для Joda-Time. Однако проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательной площадкой для возможных будущих дополнений к java.time. Среди его классов есть Interval
. Создайте Interval
, передав пару Instant
объектов. Мы можем извлечь Instant
из наших ZonedDateTime
объектов.
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
О java.time
Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как java.util.Date
, Calendar
, и SimpleDateFormat
.
Чтобы узнать больше, см. Oracle Tutorial . И поищите в Stack Overflow множество примеров и объяснений. Спецификация - JSR 310 .
Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .
Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*
занятиях. Hibernate 5 и JPA 2.2 поддерживают java.time .
Где взять классы java.time?
Joda времени
ОБНОВЛЕНИЕ: проект Joda-Time сейчас находится в режиме обслуживания и советует перейти на классы java.time . Я оставляю этот раздел нетронутым для истории.
Joda время имеет три класса для представления промежуток времени различных способов: Interval
, Period
и Duration
. У An Interval
есть определенное начало и конец на временной шкале Вселенной. Это соответствует нашей потребности в представлении «дня».
Мы вызываем метод, withTimeAtStartOfDay
а не устанавливаем время суток на нули. Из-за летнего времени и других аномалий первого момента дня может не быть 00:00:00
.
Пример кода с использованием Joda-Time 2.3.
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );
При необходимости вы можете преобразовать его в файл java.util.Date.
java.util.Date date = todayStart.toDate();