java – Android上时区错误的问题

现在正确的莫斯科时区是UTC 3.但 Android 4.4.4只知道莫斯科的UTC 4.

并且java.util.Date给出了错误的时间:

Date now = new Date();    
Sat Nov 21 00:37:24 GMT+04:00 2015
1448051844024 in (milliseconds)

使用Joda org.joda.time

DateTime nowWithCorrect = new DateTime()
                              .withZone(DateTimeZone.forID("Europe/Moscow"));
2015-11-20T23:37:24.023+03:00
1448051844024 in (milliseconds)

但问题是用户(在时区不正确的设备上)手动更正了设备上的时间.并且joda和java以毫秒为单位给出了不正确的时间.

我从Web服务时间戳和设备计算得到与当地时间不同.但当地时间不正确并给出不正确的结果.

我想检查joda和java时间并手动纠正时间戳.

问题:时区和时间之间的差异可以在几小时内变化(现在和现在是否正确)?
例如:differentTimeZone = 1,differentTimeHours = 1

最佳答案 困扰俄罗斯的时区变化

俄罗斯近年来经历了一些令人困惑的时区变化,莫斯科的offset-from-UTC在03:00至04:00之间来回转换.请参阅Time in Russia和Moscow Time上的维基百科页面.

在2011年秋天之前,莫斯科的标准时间是03:00,0700的Daylight Saving Time (DST).

从2011年秋季开始,俄罗斯决定在04:00永久停留在夏令时,并取消标准时间03:00.见this RT.com article.

2014年7月,该决定发生了巨大变化.现在俄罗斯永久性地处于03:00的标准时间并取消了DST(不再是04:00).

过时的tz数据库

因此,我认为您的麻烦是由于您的time zone tz database(以前称为Olson数据库)已过时.真正的Java平台有一个tz数据库,它的主机操作系统可能有一个tz数据库. Joda-Time有自己的tz数据库.我认为Android也是如此,尽管我不了解Android.

显然,保持所有这些tz数据库是最新的是一件真正的苦差事.

对于Joda-Time,只需用最新的Joda-Time库替换即可.虽然你可以在Joda-Time中只替换tz数据库,但据我所知,Joda-Time 2几乎没有向后兼容性问题,所以没有理由不更新整个库.但请阅读发行说明以确定.如果使用Joda-Time,这是更新的唯一最低要求;我建议更新Android,Java和主机操作系统,但不是必需的.

对于真正的Java平台,最新版本使得更新tz数据库变得更加容易.以前的版本需要一些黑客攻击.或者,更新到最新的Java 8以获取最新的库.

对于您的主机操作系统,其常规更新系统可能包含tz更新.但是,其中一些更新可能会落后.因此,您可能需要进行手动更新.

在UTC工作

日期工作的最佳实践通常是在UTC完成所有后端工作.业务逻辑,数据存储,数据库,数据交换等都应该是UTC.仅在用户或数据接收器预期/期望时调整到诸如Europe/Moscow的时区.

在Java 8及更高版本中,我们将使用内置的java.time框架.在UTC中使用Instant.指定ZoneId以在需要时区时获取ZonedDateTime.但Android 8尚未提供Java 8技术.我相信有适用于Android的java.time的后端口库,但我不知道细节.

对于Joda-Time,请询问UTC中的当前时刻.

DateTime nowUtc = DateTime.now( DateTimeZone.UTC );

如果您无法确信用户的本地设备/计算机时钟是否准确并且设置正确,则此UTC日期时间将是错误的.你无能为力.相反,信任外部源,但假定网络连接.

根据需要调整到莫斯科时间.

DateTime nowMoscow = nowUtc.withZone( DateTimeZone.forID( "Europe/Moscow" ) );

如果用户的Joda-Time的tz数据库已过时,则返回错误的结果.没办法阻止这一点,因为你无法预测俄罗斯当局在他们的时间规则旁边会做些什么.唯一的解决方案是使用具有更新的tz数据库的Joda-Time库来更新您的应用程序.或者,再次信任外部源,例如您的服务器或其他一些Web服务,但这假设是网络连接.

验证Count-From-Epoch

如果您感到困惑并希望验证日期时间对象的真实值,请查看从epoch开始的计数.

Joda-Time和旧的java.util.Date/.Calendar类从1970年UTC的第一个时刻算起milliseconds.这些值显示在问题中.看看问题中两个毫秒级的时间值是如何相同的,所以时间轴上的相同时刻,但是通过Android的Date类错误地调整到莫斯科时间(几乎可以肯定是因为过时的tz数据库).

请注意,java.time使用不同的count-from-epoch,从同一时期(1970 UTC)计算nanoseconds.在Joda-Time,请致电getMillis以获得从纪元开始的计数.在java.util.Date中,调用getTime.

点赞