Неправильное смещение часового пояса на Android после разбора JodaTime
Я пытаюсь проанализировать дату в формате ISO библиотекой JodaTime для Android, и получаю неправильное смещение часового пояса.
String dateString = "1990-05-03T20:00:00.000Z";
DateTimeFormatter inputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(DateTimeZone.UTC);
DateTimeFormatter outputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(DateTimeZone.getDefault());
DateTime dt = inputFormatter.parseDateTime(dateString);
String result = outputFormatter.print(dt);
Мой часовой пояс по умолчанию - "Европа / Москва", но результат "1990-05-04T00:00:00.000+0400", тогда как "1990-05-03T23:00:00.000+0300". Версия Android - KitKat.
Что я сделал не так?
1 ответ
Если вы хотите использовать только фактическое смещение московской зоны для отображения исторической отметки времени, вы можете использовать этот код:
String dateString = "1990-05-03T20:00:00.000Z";
DateTimeFormatter inputFormatter =
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(DateTimeZone.UTC);
DateTime dt = inputFormatter.parseDateTime(dateString);
System.out.println(dt); // 1990-05-03T20:00:00.000Z
// only use actual offset for Moscow
DateTimeZone zoneOffset =
DateTimeZone.forOffsetMillis(
DateTimeZone.forID("Europe/Moscow").getOffset(DateTime.now())
);
DateTimeFormatter outputFormatter =
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(zoneOffset);
String result = outputFormatter.print(dt);
System.out.println(result); // 1990-05-03T23:00:00.000+0300
Все тот же момент, только с разным смещением и местным временем в той части формы, которую вы ищете.
О вашем комментарии, как разобрать UTC-время с сервера:
String input = "2016-12-10T13:40:38.595";
DateTime utc =
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").parseLocalDateTime(input)
.toDateTime(DateTimeZone.UTC);
System.out.println(utc); // 2016-12-10T13:40:38.595Z
Как отправить текущее время устройства в формате UTC на сервер, если данные устройства неверны?
Сначала скажу: я все еще думаю, что лучше проектировать, если нет необходимости отправлять текущую временную метку клиента на сервер, потому что сервер должен использовать свои собственные часы для регистрации временной метки при получении клиентских сообщений. Это эффективно предотвращает фальшивые клиенты от отправки бессмысленного времени.
В противном случае, если как tz-data, так и часы устройства (через System.currentTimeMillis()
), но локальная временная метка устройства все еще верна, как указано в ваших комментариях (допустимые значения полей год-месяц-день-час-минута), тогда вы можете применить следующий обходной путь:
// incorrect platform data from device clock or outdated tz-data
long platformMillis = System.currentTimeMillis();
int offsetMillis = TimeZone.getDefault().getOffset(platformMillis);
DateTimeZone tzPlatform = DateTimeZone.forOffsetMillis(offsetMillis); // +04 on your device
// we assume correct local time if the errors of platform data compensate each other
LocalDateTime ldt = new LocalDateTime(new Date(platformMillis), tzPlatform);
// now we combine local timestamp with the tz-data of Joda-Time (hopefully up-to-date)
long utcMillis = ldt.toDateTime(DateTimeZone.getDefault()).getMillis();
Примечание: Моя библиотека Time4A позволяет использовать более короткое решение.
Moment now = SystemClock.inPlatformView().now().inStdTimezone();
long utcMillis = TemporalType.MILLIS_SINCE_UNIX.from(now);