java .time и ThreeTenABP
Чтобы получить объект даты и времени с указанным c часовым поясом, откройте java .time, современный Java API даты и времени. Я пишу код Java, это то, что я могу, и надеюсь, что вы переведете:
ZoneId london = ZoneId.of("Europe/London");
Date date = getOldfashionedDateFromSomewhere();
System.out.println("Original Date: " + date);
ZonedDateTime dateTimeLondon = date.toInstant().atZone(london);
System.out.println("Date-time in London: " + dateTimeLondon);
Пример вывода:
Original Date: Tue Jun 16 13:14:59 GMT+03:00 2020
Date-time in London: 2020-06-16T11:14:59+01:00[Europe/London]
A Date
не получил, так как не может иметь часовой пояс. Да, я знаю, когда вы его распечатываете, неявно вызывая его метод toString
, он печатает часовой пояс. Что происходит, так это то, что он захватывает часовой пояс по умолчанию вашей JVM и использует его для рендеринга строки. Итак, пока настройка часового пояса вашей JVM равна GMT + 03: 00, все ваши Date
объекты всегда будут печатать этот часовой пояс.
Итак, если (в каком-то другом проекте) мне нужна дата с часовым поясом лучше использовать java .time.ZonedDateTime (java 8)?
По крайней мере, так я бы рекомендовал. Как я уже сказал, использование Date
- это не способ. Вот несколько способов:
- Плохой и устаревший способ: использовать
GregorianCalendar
. - Лучший способ: использовать
DateTime
от Joda-Time. Если вы принимаете внешнюю зависимость, я бы предпочел ThreeTenABP. - Хороший способ:
ZonedDateTime
из java .time. - Продвинутый способ: использование Time4J. У меня нет опыта, поэтому я бы не стал рекомендовать за или против. Если у вашего проекта есть требования, которые go превосходят то, что предлагает java .time, я бы обязательно исследовал этот вариант.
Что пошло не так в вашем коде
Во-первых, вы вероятно, не следует устанавливать часовой пояс на GMT + 03: 00. Хотя в вашем часовом поясе сейчас используется это смещение по Гринвичу, это не означает, что оно всегда использовалось и будет всегда. Для правильных результатов для исторических c и будущих дат используйте идентификатор реального часового пояса, такой как Африка / Найроби или Европа / Москва, то есть в формате регион / город . Так же, как вы использовали Europe/London
для времени Briti sh (к счастью, не GMT+00:00
).
Я уже упоминал второй момент: вы не можете использовать Date
для даты и времени со временем пояс, потому что Date
не имеет часового пояса. A Date
- это момент времени, не больше и не меньше.
Далее, 2020-06-16T11:14:59.000Z
неверно для времени в Лондоне. 11:14:59 - правильное время суток. Z
означает UT C или смещение 0 от UT C и неверно, так как Великобритания использует летнее время (DST) и, следовательно, находится со смещением +01: 00 в июне (как говорится в выводе моего кода выше) . Время по смещению Z
было бы 10:14:59. Другими словами, у вас выходной на 1 час. Это определение Z
является частью стандарта ISO 8601. Ваш формат JSON - это формат ISO 8601. Я включаю ссылку внизу. Поскольку Z
является смещением, вы всегда должны форматировать и анализировать его как таковое, а никогда жестко кодировать его как литерал в строке шаблона формата.
Ваше преобразование обратно из строки в Date
показывает ту же ошибку, поэтому она уравновешивается ошибкой преобразования в String
, и вам удается вернуть эквивалентный объект Date
.
Это старый проект Android. И я не могу использовать java .time. Я могу использовать только java .util.Date
Конечно, вы можете использовать java .time в старых Android проектах и для старых Android версий.
- В Java 8 и новее, а также на новых Android устройствах (начиная с уровня API 26) современный API встроен.
- В не- Android Java 6 и 7 получите ThreeTen Backport, бэкпорт современных классов (ThreeTen для JSR 310; см. ссылки внизу).
- On (более ранние) Android используйте Android версию ThreeTen Backport. Это называется ThreeTenABP. И убедитесь, что вы импортируете классы даты и времени из
org.threeten.bp
с подпакетами.
Ссылки