JodaTime解析后Android上的时区偏移错误

时间:2016-12-10 10:03:30

标签: android datetime timezone jodatime android-jodatime

我尝试用JodaTime库为android解析ISO格式的日期,并得到错误的时区偏移。

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 个答案:

答案 0 :(得分:4)

如果您只想使用实际的莫斯科区域偏移来显示历史时间戳,那么您可以使用以下代码:

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数据和设备时钟(通过System.currentTimeMillis())都错误,但本地设备时间戳仍然正确,如评论中所示(年 - 月 - 日 - 小时的有效字段值-minute)然后你可以应用以下解决方法:

// 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);