тл; д-р
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 напіввідкритим", щоб переглянути більше обговорень та прикладів.
Дивіться цю публікацію, Білль Шнайдер , часові інтервали та інші діапазони повинні бути напіввідкритими .
Уникайте застарілих занять з датами
Класи java.util.Date та .Calendar, як відомо, непросто. Уникайте їх.
Використовуйте java.time заняття . Java.time структура є офіційним наступником досить успішною Joda-Time бібліотеки.
java.time
Рамка java.time вбудована в Java 8 та новіші версії. Перенесено назад на Java 6 і 7 у програмі ThreeTen-Backport , додатково адаптований до Android у проекті ThreeTenABP .
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 );
Використовуючи напіввідкритий підхід, отримайте перший момент наступного дня.
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 . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація - JSR 310 .
Проект Joda-Time , який зараз знаходиться в режимі обслуговування , радить перейти до класів java.time .
Ви можете обмінюватися об'єктами java.time безпосередньо зі своєю базою даних. Використовуйте драйвер JDBC, сумісний з JDBC 4.2 або пізнішої версії. Немає потреби в струнах, немає потреби в java.sql.*заняттях. Hibernate 5 & JPA 2.2 підтримують java.time .
Де отримати класи java.time?
Joda-Time
ОНОВЛЕННЯ: Проект Joda-Time зараз перебуває в режимі обслуговування та радить перейти на java.time класів . Цей розділ я залишаю недоторканим для історії.
Joda час має три класи для подання проміжок часу різних способів: Interval, Periodі Duration. AnInterval має певний початок і закінчення на часовій шкалі Всесвіту. Це відповідає нашій потребі представляти "день".
Ми називаємо метод 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();