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

JodaTime解析后Android上的时区偏移错误,android,datetime,timezone,jodatime,android-jodatime,Android,Datetime,Timezone,Jodatime,Android Jodatime,我试图通过android的JodaTime库解析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 = D

我试图通过android的JodaTime库解析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


我做错了什么?

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

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()
)都错误,但本地设备时间戳仍然正确,如您的注释所示(年-月-日-小时-分钟的有效字段值),则您可以应用以下解决方法:

// 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();
旁注:我的库支持一个较短的解决方案

Moment now = SystemClock.inPlatformView().now().inStdTimezone();
long utcMillis = TemporalType.MILLIS_SINCE_UNIX.from(now);

我想,没什么不对的。1990年05月03日是夏季(5月),因此对于欧洲/莫斯科,Joda time使用夏季时间偏移量+04:00。也许你只是感到困惑,因为事实上,莫斯科是在冬天。@MenoHochschild 2014年以来,俄罗斯只有冬天,我们每年都不会改变时间。如何在Joda time中禁用夏季/冬季时间?这是工作。但是如果我在所有时区都使用这样的代码呢
DateTimeZone zoneOffset=DateTimeZone.forOffsetMillis(DateTimeZone.getDefault().getOffset(DateTime.now());DateTimeFormatter outputFormatter=DateTimeFormat.forPattern(“yyyy-MM-dd'T'HH:MM:ss.SSSZ”)。带区域(区域偏移)@preceptron为什么不在其他时区工作?您可以显示任意偏移量的任何瞬间,保留该瞬间,但更改本地时间戳。然而,对我来说,带有历史偏移量的历史形式似乎更为自然,而不是你要求只使用与要显示的时间戳无关的实际偏移量。@preceptron也许这更清楚了:假设你不是在莫斯科,而是在巴西,因此,您可以显示与圣保罗区偏移相同的瞬间,从而生成巴西的本地时间戳。本地时间戳部分和偏移量更改,但瞬间仍然相同。这实际上取决于你想用哪个偏移量来显示。如果您只是指示Joda Time使用莫斯科区域(没有明确说明偏移量),那么Joda Time将使用上下文历史瞬间(即将打印)给出的偏移量。我们在服务器上使用UTC时间。在iOS和新版Android上,时区的偏移量正确(莫斯科为+3),但KitKat的偏移量为+4(莫斯科为+4)(这是错误的)。所以,我应该在图书馆旁边修好它。我还有一个问题。我试图得到UTC字符串,但如果我得到当前时间,我会得到-4小时的字符串…但我需要-3。。。例如,现在10.12.2016 16:40,我得到了UTC字符串,比如“2016-12-10T13:40:38.595”,我尝试了不同的方法,但它不起作用。你能帮我解决这个问题吗?@preceptron查看我答案的更新(下半部分)。