tl; dr
Ваш ввод недействителен , так как BST
(Британское летнее время) зимой не действовал.
BST
не может бытьНадежно проанализирован, так как это нестандартная неуникальная псевдозона.
Нет необходимости возиться с SimpleDateFormat
.Пусть современные java.time классы делают тяжелую работу.
И хотя я хотел бы не поддерживать java.util.Date
, для меня это не вариант.
По краям вашего кода, конвертировать в-из старых и современных классов.
// Convert from legacy to modern.
Instant instant = myJavaUtilDate.toInstant() ;
// Convert from modern to legacy.
java.util.Date myJavaUtilDate = Date.from( instant ) ;
Нет BST
зимой
Видимо, «B» в вашем BST
означаетбыть британцемНо BST
в этом контексте означает Британское летнее время .Это означает Летнее время (DST) , которое задействовано летом, а не зимой.Так что ваша входная строка январской даты в сочетании с BST
бессмысленна .
Double-Summertime
Есть еще одно осложнение в вашем примере с моментом в 1970 годус британским часовым поясом.
Практика перехода на летнее время в Великобритании с использованием смещения на один час впереди UTC (+01: 00) летом и смещения нуля (+00: 00) зимойСтандартное время составляет текущая практика.Это не всегда имело место.
В 1970 году Великобритания испытывала "двойное летнее время" .В этом эксперименте 1968–1971 годов зимнее время было на один час впереди UTC, а не на ноль, а летнее время было на два часов впереди UTC вместо одного часа, используемого в настоящее время.Это привело к тому, что британское время стало больше похожим на континентальную Европу, и мы надеялись сократить количество аварий.В то время как в январе 2019 года мы не ожидаем скачка, время в Британии будет таким же, как в UTC (смещение от UTC, равное нулю, часам, минутам и секундам).
Избегать псевдозон
Избегать этих 2-4-символьных псевдозон, таких как BST
.Они не стандартизированы.Они даже не уникальны!Таким образом, BST
можно интерпретировать как часовой пояс Pacific/Bougainville
, а также British Summer Time
.
Укажите правильное имя часового пояса в форматеContinent/Region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
.Никогда не используйте 2-4 буквенные сокращения, такие как BST
или EST
или IST
, поскольку они не истинных часовых поясов, не стандартизированы и даже не уникальны (!).
Преобразование
Вы можете легко конвертировать между устаревшими и современными классами даты и времени.Новые методы преобразования были добавлены к старым классам.Ищите методы from
, to
и valueOf
для соглашений об именах .
java.util.Date
⇄ java.time.Instant
java.util.GregorianCalendar
⇄ java.time.ZonedDateTime
java.sql.Date
⇄ java.time.LocalDate
java.sql.Timestamp
⇄ java.time.Instant
Преобразование
1118 * Ваш входной строкой 00:00 1 января 1970 г. случается
эпоха базисная дата используется как наследие и современные классы даты и времени.У нас есть константа для этого значения.
Instant epoch = Instant.EPOCH ;
instant.toString (): 1970-01-01T00: 00: 00Z
Посмотрите тот же момент через вашчасовой пояс Europe/London
.
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = epoch.atZone( z ) ;
zdt.toString (): 1970-01-01T01: 00 + 01: 00 [Европа / Лондон]
Обратите внимание, что вышеупомянутый Double-Summertime эксперимент действует тогда.Если мы попробуем тот же код для 2019 года, мы получим смещение от UTC с нулём.
ZonedDateTime zdt2019 =
Instant
.parse( "2019-01-01T00:00Z" )
.atZone( ZoneId.of( "Europe/London" ) )
;
zdt2019.toString (): 2019-01-01T00:00Z [Европа / Лондон]
Чтобы преобразовать в java.util.Date
, нам нужен объект java.time.Instant
.Instant
представляет момент в UTC.Мы можем извлечь Instant
из нашего ZonedDateTime
объекта, эффективно адаптируясь от зоны к UTC.В тот же момент, другое время настенных часов.
Instant instant = zdt.toInstant():
Теперь мы должны вернуться туда, где мы начали, в базовую дату 1970-01-01T00: 00: 00Z.
мгновенно.toString (): 1970-01-01T00: 00: 00Z
Чтобы получить объект java.util.Date
, вам может потребоваться взаимодействие со старым кодом, который еще не обновлен до java.time классы, используйте новый метод Date.from
, добавленный к старому классу.
java.util.Date d = Date.from( instant ) ; // Same moment, but with possible data-loss as nanoseconds are truncated to milliseconds.
d.toString (): чт янв 01 00:00:00 GMT 1970
Кстати, помните о возможной потере данных при преобразованииот Instant
до Date
.Современные классы имеют разрешение наносекунд , тогда как устаревшие классы используют миллисекунд .Таким образом, часть вашей доли секунды может быть усечена.
См. Весь код выше run live на IdeOne.com .
Чтобы преобразовать другое направление, используйте Date::toString
метод.
Instant instant = d.toInstant() ;
ISO 8601
Избегайте использования текста в пользовательских форматах для обмена значениями даты и времени.При сериализации значений времени и даты в виде удобочитаемого текста используйте только стандартные форматы ISO 8601 .Классы java.time по умолчанию используют эти форматы.
Те строки, с которыми вы экспериментировали, разбирались в формате ужасный и никогда не должны использоваться для обмена данными.
О 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 .