В моей стране мы больше не соблюдаем летнее время. Теперь мы используем стандартное время круглый год.
Поэтому многие устройства столкнулись с проблемой. Я использовал разные подходы, чтобы исправить это, но только один из них работает правильно.
Я пытаюсь преобразовать время эпохи в местное время. Например
val epocTime = 1715244851730 // 12:24:11.730 PM GMT+03:30
Когда я использую SimpleDateFormat, я получаю неверный результат.
java.text.SimpleDateFormat("HH:mm", Locale.getDefault(Locale.Category.FORMAT))
.format(Date(time)) // 13:24
Кроме того, когда я использую java.time.LocalDateTime, я получаю неправильный результат.
java.time.LocalDateTime.ofInstant(
java.time.Instant.ofEpochMilli(epocTime),
java.time.ZoneId.systemDefault()
) // 13:24:11.730
Но когда я использую библиотеку ThreeTen, я получаю правильный результат
org.threeten.bp.LocalDateTime.ofInstant(
org.threeten.bp.Instant.ofEpochMilli(epocTime),
org.threeten.bp.ZoneId.systemDefault(),
) // 12:24:11.730
Итак, вопрос: не является ли java time заменой ThreeTen библиотеки?
Android 10 и более поздних версий должны регулярно получать обновления данных о часовых поясах. android-developers.googleblog.com/2024/03/…
Предупреждение: насколько я понимаю, эмулятор имеет tzdata только с момента выпуска версии ОС и НЕ обновляется.
Поэтому для старых устройств, которые больше не получают tzdata обновлений, вам нужно будет использовать стороннюю библиотеку, например joda-time-android , которая, похоже, обновляет tzdata с некоторой частотой, но имейте в виду, что вам нужно будет обновить app, если вы хотите сохранить согласованность с текущим набором tzdata.
Аналогичная ситуация существует для ThreeTenABP / ThreeTen Backport, где вам необходимо обновить библиотеку до самой последней версии, чтобы получать tzdata обновления.
Ответ Чанга правильный: когда правила часового пояса, интересующего ваших пользователей, меняются, база данных правил часового пояса должна быть обновлена. Ни один компьютер не является ясновидящим; вы должны информировать каждый компьютер об изменении правил.
Имейте в виду, что правила часовых поясов (tzdata) необходимо обновить во всех этих местах:
Вы сказали:
Я пытаюсь преобразовать время эпохи в местное время.
Чтобы проанализировать количество миллисекунд с момента ссылки на эпоху первого момента 1970 года по всемирному координированному времени (1970-01-01T00:00Z), используйте класс java.time.Instant.
Вот пример синтаксиса Java, поскольку я еще не знаю Kotlin.
Instant instant = Instant.ofEpochMilli( 1_715_244_851_730L ) ;
Когда я использую SimpleDateFormat,
Нет, никогда не используйте SimpleDateFormat. Ужасно несовершенные классы даты и времени из первых дней Java были много лет назад вытеснены современными классами java.time, определенными в JSR 310.
Реализация java.time доступна в Android 26+. Для более ранних версий Android современные инструменты делают доступной большую часть функций java.time через «API Desugaring».
также, когда я использую java.time.LocalDateTime, я получаю неправильный результат
Нет, никогда не используйте LocalDateTime для обозначения момента, конкретной точки на временной шкале. Этот класс содержит только дату и время суток, но ему не хватает контекста часового пояса или смещения от UTC. Таким образом, объект LocalDateTime по своей сути неоднозначен.
Чтобы представить момент, конкретную точку на временной шкале, используйте любой из этих трех классов java.time:
InstantOffsetDateTimeZonedDateTimeВ вашем случае используйте ZonedDateTime.
ZoneId z = ZoneId.of( "Asia/Tehran" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Посмотрите этот код запустите на Ideone.com.
2024-05-09T08:54:11.730Z
2024-05-09T13:24:11.730+04:30[Asia/Tehran]
Убедитесь, что в этот момент не наблюдается летнее время.
ZoneRules rules = z.getRules() ;
boolean isDst = rules.isDaylightSavings( instant ) ;
Но когда я использую библиотеку ThreeTen, я получаю правильный результат
Предположительно, вы загрузили свежую копию ThreeTen-Backport, которая поставляется с собственной обновленной копией tzdata. Таким образом, он производит правильные настройки часового пояса, тогда как другой код дает неправильные результаты, используя устаревший файл tzdata.
Итак, вопрос: не является ли время Java заменой библиотеки ThreeTen?
Не совсем.
Библиотека ThreeTen-Backport, как следует из названия, представляет собой обратный порт функциональности java.time из Java 8+ обратно в более старые версии Java 6 и Java 7.
API (имена классов, методов и т. д.) практически идентичны, что облегчает последующую миграцию старых приложений на современную Java.
В ThreeTen-Backport больше нет необходимости, поскольку Java 6 и 7 действительно устарели и не поддерживаются. Приложения следует перенести на LTS версию Java. Версии LTS включают Java 8, 11, 17 и 21. Все эти современные версии Java включают классы java.time. Я настоятельно рекомендую 17 и 21, так как срок службы 8 заканчивается, и большинство приложений, которые могут работать на 11, должны работать и 21/17.
Не путайте ТриТен-Бэкпорт с ТриТен-Экстра. Вторая — жизненно важная библиотека, расширяющая java.time дополнительными функциями.
java.timeи ThreeTen Backport по сути одинаковы. Откуда каждый из них получает данные о часовом поясе на устройстве Android и в симуляторе Android, я не знаю. Похоже, вам нужно где-то обновить tzdata, что должно быть возможно.