ТЛ; др
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
ZonedDateTime start = today.with( TemporalAdjusters.firstDayOfMonth() )
.atStartOfDay( z ) ;
ZonedDateTime stop = today.with( TemporalAdjusters.firstDayOfNextMonth() )
.atStartOfDay( z ) ;
- Для определения даты требуется часовой пояс.
- Лучше указать явно, чем неявно полагаться на текущий часовой пояс JVM по умолчанию.
Избегайте старых классов
Вы используете проблемные старые классы даты и времени, теперь устаревшие, замененные классами java.time.
Использование java.time
Эта работа намного проще с классами java.time.
LocalDate
Класс LocalDate
представляет значение только для даты без времени суток и без часового пояса.
Часовой пояс
Часовой пояс имеет решающее значение при определении даты. В любой момент времени дата меняется по всему земному шару в зависимости от зоны. Например, через несколько минут после полуночи в Париж Франция - это новый день, а еще "вчера" в Монреаль Квебек .
Укажите собственное имя часового пояса в формате continent/region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте 3-4-буквенное сокращение, например EST
или IST
, так как они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
Всегда указывайте часовой пояс явно. Если опущен, текущий часовой пояс JVM по умолчанию применяется неявно. Это значение по умолчанию может быть изменено в любой момент с помощью любого кода любого приложения в JVM. Поэтому, если это важно, попросите пользователя указать желаемый / ожидаемый часовой пояс. Если это не имеет решающего значения, вы можете попросить явное значение по умолчанию, чтобы прояснить свои намерения в коде, а не двусмысленность, основанную на неявном значении по умолчанию.
ZoneId z = ZoneId.systemDefault(); // Get JVM’s current default time zone.
LocalDate today = LocalDate.now( z );
TemporalAdjuster
Интерфейс TemporalAdjuster
предоставляет классы, которые могут настраивать значения даты и времени. Класс TemporalAdjusters
предоставляет несколько удобных реализаций.
LocalDate firstOfThisMonth = today.with( TemporalAdjusters.firstDayOfMonth() );
ZonedDateTime
Чтобы превратить эту дату только в дату-время-день, примените часовой пояс ZoneId
, чтобы получить объект ZonedDateTime
.
Не думайте, что первый момент дня - 00:00:00. Из-за таких аномалий, как летнее время (DST), первый момент может быть чем-то вроде времени 01:00:00. Пусть java.time выяснит это, позвонив atStartOfDay
.
ZonedDateTime zdtStartOfMonth = firstOfThisMonth.atStartOfDay( z );
Half-Open
Вы ошибаетесь, пытаясь определить последний момент месяца. Этот последний момент имеет бесконечно делимую дробную секунду. Попытка разрешить конкретную гранулярность нецелесообразна, поскольку разные системы используют разные гранулярности. Старые классы даты и времени Java используют миллисекунды, некоторые базы данных, такие как Postgres, используют микросекунды, классы java.time используют наносекунды, а другие системы используют другие варианты.
Более мудрым подходом, обычно используемым в работе с датой и временем для определения промежутков времени, является Half-Open, где начало включительно , а окончание эксклюзив . Это означает, что месяц начинается с первого момента первого числа месяца и продолжается, но не включает первый момент первого числа месяца , следующего за .
LocalDate firstOfNextMonth = today.with( TemporalAdjusters.firstOfNextMonth() );
Настройтесь на часовой пояс, чтобы получить определенный момент.
ZonedDateTime zdtStartOfNextMonth = firstOfNextMonth.atStartOfDay( z );
Логика для сравнения момента с этим промежутком времени: «Этот момент (а) равен или после начала, и (б) меньше конца?». Обратите внимание на отсутствие «или равно» в части «б». Это означает, что мы приближаемся к финалу, но не включая его.
Кроме того, более короткий способ сказать часть «а» - «не до начала». Таким образом, мы можем спросить более просто: «Этот момент не перед началом И не перед окончанием?».
ZonedDateTime moment = ZonedDateTime.now( z );
Boolean spanContainsMoment = ( ! moment.isBefore( zdtStartOfMonth ) ) && ( moment.isBefore( zdtStartOfNextMonth ) ) ;
Кстати, стандартный формат ISO 8601 для форматирования текстового представления промежутка времени использует символ косой черты для соединения начала и конца.
String output = zdtStartOfMonth.toString() + "/" + zdtStartOfNextMonth.toString() ;
Interval
Вы можете представитьt этот промежуток времени с использованием класса Interval
в библиотеке ThreeTen-Extra .Этот класс отслеживает начало и конец в UTC как Instant
объектов.Вы можете извлечь Instant
из ZonedDateTime
объекта.
Interval interval = Interval.of( zdtStartOfMonth.toInstant() , zdtStartOfNextMonth.toInstant() );
YearMonth
Кстати, вы можете найти класс YearMonth
полезен в вашей работе.
О java.time
В java.time интегрирован фреймворкЯва 8 и позже.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
, & SimpleDateFormat
.
Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .
Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .
Вы можете обмениваться java.time объектами непосредственно с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.*
классах.
Где получить классы java.time?
- Java SE 8 , Java SE 9 , Java SE 10, а позже
- Встроенный.
- Часть стандартного Java API с встроенной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и Java SE 7
- Android
- Более поздние версии реализации связки Android классов java.time.
- Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .
ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Вы можете найти здесь несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и more .