ТЛ; др
Проблема: Вы ошибочно меняете дату, а не только время суток. Кроме того, часовой пояс неявно применяется.
Решение: Вместо этого используйте современные java.time классы.
LocalDate
.now() // Better to explicitly pass the desired/expected time zone as a `ZoneId` object.
.atStartOfDay() // Again, better to explicitly pass the desired/expected time zone as a `ZoneId` object.
Возвращает LocalDateTime
( ВНИМАНИЕ: Не мгновение, не точка на временной шкале).
2018-11-01T00: 00
Намного лучше указать часовой пояс.
LocalDate
.now(
ZoneId.of( "Pacific/Auckland" )
)
.atStartOfDay(
ZoneId.of( "Pacific/Auckland" )
)
Возвращает ZonedDateTime
. Это является моментом, является точкой на временной шкале.
2018-11-02T00: 00 + 13: 00 [Pacific / Auckland]
GregorianCalendar::setTimeInMillis
это не установка времени суток
Очевидно, вы ошибочно полагали, что GregorianCalendar::setTimeInMillis
установит время суток, не влияя на дату. Среди многих недостатков унаследованных классов даты и времени есть несколько очень плохих вариантов именования классов и методов.
Но, нет, этот метод переопределяет момент как количество миллисекунд с эталонной даты 1970-01-01T00: 00Z.
Добавьте часовой пояс, неявно присвоенный GregorianCalendar
, и вы получите неожиданные результаты.
Я начал немного тестировать с Java-GregorianCalendar
Не.
Эти старые классы даты и времени, включенные в ранние версии Java, ужасны . Они были вытеснены несколько лет назад классами java.time , определенными в JSR 310 .
В частности, чтобы отслеживать момент в UTC, используйте Instant
.
инициализация объекта в миллисекундах
Не.
Время отслеживания в виде отсчета от эпохи подвержено ошибкам. В промышленности используется много разных дат эпохи . В отрасли используются разные степени детализации (целые секунды, миллисекунды, микросекунды, наносекунды).
Так что отсчет времени неоднозначен. Также склонен к путанице и пропущенным ошибкам, потому что люди не могут прочитать значение значений.
При обмене значениями даты и времени вместо этого используйте строки в стандартном формате ISO 8601.
Когда передается отсчет миллисекунд от эпохи Unix первого момента 1970 года в UTC, анализируется как Instant
.
Instant instant = Instant.ofEpochMilli( … ) ;
java.time
Современное решение использует java.time классы вместо.
Получите ваше свидание.
LocalDate
Класс LocalDate
представляет значение только для даты без времени суток и без часовой пояс или смещение от UTC .
Часовой пояс имеет решающее значение при определении даты. В любой момент времени дата меняется по всему земному шару в зависимости от зоны. Например, через несколько минут после полуночи в Париж Франция - это новый день, а еще «вчера» в Монреаль Квебек .
Если часовой пояс не указан, JVM неявно применяет свой текущий часовой пояс по умолчанию. Это значение по умолчанию может измениться в любой момент во время выполнения (!), Поэтому ваши результаты могут отличаться. Лучше указать в качестве аргумента ваш желаемый / ожидаемый часовой пояс .
Укажите собственное имя часового пояса в формате continent/region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте 2-4-буквенное сокращение, такое как EST
или IST
, поскольку они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Если вы хотите использовать текущий часовой пояс JVM по умолчанию, запросите его и передайте в качестве аргумента. Если опущено, текущее значение по умолчанию JVM применяется неявно. Лучше быть явным, поскольку значение по умолчанию может быть изменено в любой момент во время выполнения любым кодом в любом потоке любого приложения в JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Или укажите дату. Вы можете установить месяц по номеру, с нормальным номером 1-12 для января-декабря.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Или, беттну, используйте предварительно определенные объекты перечисления Month
, по одному на каждый месяц года. Совет: используйте эти Month
объекты по всей вашей кодовой базе, а не просто целое число, чтобы сделать ваш код более самодокументируемым, обеспечить допустимые значения и обеспечить безопасность типов .
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
ZonedDateTime
Видимо, вы хотите первый момент дня. Кстати, не думайте об этом как о «полуночи», так как этот термин неоднозначен.
Первый момент дня не может быть 00:00. Аномалии, такие как переход на летнее время (DST), означают, что первым моментом некоторых дат в некоторых зонах может быть другой момент, например 01:00. Пусть java.time определит первый момент.
Укажите часовой пояс.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = localDate.atStartOfDay( z ) ;
Если вы хотите увидеть тот же момент в UTC, извлеките Instant
.
Instant instant = zdt.toInstant() ;
О java.time
Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
, & SimpleDateFormat
.
Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .
Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .
Вы можете обмениваться java.time объектами непосредственно с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.*
классах.
Где получить классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и more .