gpt4 book ai didi

java - 在给定时区的 Android 上检索当前时间的错误

转载 作者:行者123 更新时间:2023-11-29 19:34:12 24 4
gpt4 key购买 nike

在我的应用程序中,我从网络服务中检索一个 unix 时间戳( future 0 到 15 分钟之间),并以 XXm-XXs 的形式显示该时间的倒计时。因此,我只需执行 System.currentTimeMillis() - timestamp 并将结果转换为人类可读的日期。一切正常,但似乎在某些时区,我的计时器关闭了 30 分钟,因为 System.currentTimeMillis() 返回的值比预期低 1800000 毫秒 因为日历返回错误当我用它请求分钟时的分钟值。时区是吉隆坡(马来西亚)的 GMT+8。使用另一个 GMT+8 时区可以正常工作。示例:

 long till = requestTimeFromWebService()
long now=System.currentTimeMillis();
long remaining_time = till - now;
Calendar c=Calendar.getInstance();
c.setTimeInMillis(remaining_time);
int minutes=c.get(Calendar.MINUTE);
System.out.println(""+minutes+"m");
int seconds=c.get(Calendar.SECOND);
System.out.println(""+seconds+"s");

使用此代码 System.out.println(""+minutes+"m"); 打印(例如)5m 如果设置了 GMT+2 罗马时区并且 35m 如果设置了 GMT+8 吉隆坡时区。

这是一个已知错误吗?我发现了这个:http://www.objectdb.com/database/forum/363这似乎证实了一个问题。

我还发现了这个:https://en.wikipedia.org/wiki/Time_in_Malaysia

Blockquote At 2330 hrs local time of 31 December 1981, people in Peninsular Malaysia adjusted their clocks and watches ahead by 30 minutes to become 00:00 hours local time of 1 January 1982, to match the time in use in East Malaysia, which is UTC+08:00. This could explain where the bug comes off.

有什么建议吗?

最佳答案

日期时间 != 时间跨度

您正在滥用日期时间类 java.util.Calendar(或 java.util.Date)来不恰本地跟踪时间跨度。该类以 UTC(1970-01-01T00:00:00Z)加上分配的时区自 1970 年开始以来的毫秒数来跟踪时间。

因此,当您使用 5 分钟的毫秒数进行实例化时,您实际上是在 1970 年 1970-01-01T00:05:00Z 开始后创建 5 分钟的日期时间java.util.Date 并为 java.util.Calendar 添加时区。

当您为马来西亚应用时区时,您最终得到的是 1970 年的旧式马来西亚时间规则,而不是今天 1981 年后的马来西亚规则。

所以,没有错误,只是对功能的滥用。

经验教训:不要使用日期时间值来表示时间跨度。

java.time

另一个问题:您正在使用臭名昭著的旧旧日期时间类,现在已被 java.time 类取代。

如果“unix 时间戳”是指从 1970 年开始在 UTC 中计算的毫秒数例如 1_473_738_754_764L,然后使用 Instant类(class)。 Instant class 代表时间轴上的一个时刻 UTC分辨率为 nanoseconds .

首先,我们将问题中描述的一些输入数据模拟为 future 15 分钟。

Instant instantNow = Instant.now ();
long seconds = TimeUnit.MINUTES.toSeconds ( 10 );
String input = Long.toString ( instantNow.plusSeconds ( seconds ).toEpochMilli () ); // 10 minutes in the future.

为了处理该 String 输入,我们将其转换为 long 原始值,并将其提供给 Instant 工厂方法。

Instant instantLater = Instant.ofEpochMilli ( Long.valueOf ( input ) );

时间跨度

要捕获耗时,请使用 Duration类。

Duration duration = Duration.between ( instantNow , instantLater );

System.out.println ( "instantNow: " + instantNow + " | instantLater: " + instantLater + " | duration: " + duration );

运行时。注意标准ISO 8601持续时间的格式 PnYnMnDTnHnMnS,其中 P 标记开始,T 将年-月-日部分与时-分-秒部分分开.所以 PT10M 是“十分钟”。始终将此格式用于耗时的文本表示,而不是模棱两可的时钟样式 (HH:MM:SS)。 java.time 中的DurationPeriod 类可以直接解析并生成此类字符串,无需指定格式化模式。

instantNow: 2016-09-13T19:16:33.913Z | instantLater: 2016-09-13T19:26:33.913Z | duration: PT10M

请注意,以上代码均不关心时区。所有值都在 UTC 中.您的大部分业务逻辑、数据存储和数据交换都应该使用 UTC。仅在必要时或为了向用户展示而使用分区值。

分区

您的问题询问的是罗马和马来西亚的分区值。应用 ZoneId 以获得 ZonedDateTime。指定 proper time zone name .切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId zMontreal = ZoneId.of ( "America/Montreal" );
ZoneId zRome = ZoneId.of ( "Europe/Rome" );
ZoneId zKualaLumpur = ZoneId.of ( "Asia/Kuala_Lumpur" );

ZonedDateTime zdtMontreal = instantNow.atZone ( zMontreal );
ZonedDateTime zdtRome = instantNow.atZone ( zRome );
ZonedDateTime zdtKualaLumpur = instantNow.atZone ( zKualaLumpur );

System.out.println ( "instantNow: " + instantNow + " | zdtMontreal: " + zdtMontreal + " | zdtRome: " + zdtRome + " | zdtKualaLumpur: " + zdtKualaLumpur );

instantNow: 2016-09-13T20:23:34.280Z | zdtMontreal: 2016-09-13T16:23:34.280-04:00[America/Montreal] | zdtRome: 2016-09-13T22:23:34.280+02:00[Europe/Rome] | zdtKualaLumpur: 2016-09-14T04:23:34.280+08:00[Asia/Kuala_Lumpur]

关于java - 在给定时区的 Android 上检索当前时间的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39441953/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com