Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/216.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在给定时区的Android上检索当前时间的错误_Java_Android_Date_Timezone_Unix Timestamp - Fatal编程技术网

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

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

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

使用此代码
System.out.println(“+minutes+m”)打印(例如)
5m
;如果设置了GMT+8吉隆坡时区,则打印
35m

这是已知的bug吗? 我发现:这似乎证实了一个问题

我还发现:

区块引用1981年12月31日当地时间23时30分,马来西亚半岛的人们将他们的时钟和手表提前30分钟调整为1982年1月1日当地时间00:00,以匹配东马来西亚使用的时间,即UTC+08:00。 这可以解释bug从何而来


有什么建议吗?

虽然我仍然不知道为什么原始代码不起作用,但我可以使用

Calendar c=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
而不是

Calendar c=Calendar.getInstance();
因此,我总是可以将时间戳与我感兴趣的UTC时区进行比较

顺便说一句,在我的情况下,日历应该可以工作,甚至可以设置区域设置时区(这是在没有参数传递到
getInstance()
)时发生的情况),它可以用于大多数时区,但显然不适用于所有人。

A date time!=时间跨度 您正在滥用日期时间类
java.util.Calendar
(或
java.util.date
)来不适当地跟踪时间跨度。该类以UTC(
1970-01-01T00:00:00Z
)加上指定的时区,以毫秒为单位跟踪从1970年开始的时间

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

当你为马来西亚申请时区时,你最终得到的是1970年的老式马来西亚时间规则,而不是今天1981年后的马来西亚规则

所以,没有bug,只是误用了功能

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

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

如果“unix时间戳”是指从1970年开始的毫秒计数,例如
1\u 473\u 738\u 754\u 764L
,则使用该类。该类表示时间线上的一个时刻,分辨率为

首先,我们模拟一些输入数据,如前面所述,这些数据将在未来15分钟内出现

Instant instantNow = Instant.now ();
long seconds = TimeUnit.MINUTES.toSeconds ( 10 );
String input = Long.toString ( instantNow.plusSeconds ( seconds ).toEpochMilli () ); // 10 minutes in the future.
为了处理该字符串输入,我们将其转换为
long
原语值,并将其提供给
即时
工厂方法

Instant instantLater = Instant.ofEpochMilli ( Long.valueOf ( input ) );
时间跨度 要捕获经过的时间,请使用类

跑步的时候。注意持续时间的标准格式
PnYnMnDTnHnMnS
,其中
P
标记开始,而
T
将年-月-日部分与时-分-秒部分分开。所以
PT10M
是“十分钟”。始终将此格式用于已用时间的文本表示,而不是不明确的时钟样式(HH:MM:SS)。java.time中的
Duration
Period
类可以直接解析和生成这样的字符串,而无需指定格式模式

瞬间时间:2016-09-13T19:16:33.913Z |瞬间时间:2016-09-13T19:26:33.913Z |持续时间:PT10M

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

分区 您的问题询问了罗马和马来西亚的分区价值。应用
ZoneId
以获取
zoneDateTime
。指定一个。切勿使用3-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

时间:2016-09-13T20:23:34.280Z合同:2016-09-13T16:23:34.280-04:00[美国/蒙特利尔]时间:2016-09-13T22:23:34.280+02:00[欧洲/罗马];吉隆坡:2016-09-14T04:23:34.280+08:00[亚洲/吉隆坡]


30000毫秒
这是30秒,而不是30分钟。您的设备的日期是什么?某些时区与UTC相差不到一小时:。此外,您还可以获取用户的UTC偏移量,并使用该偏移量:嗯,这里有些东西没有意义
System.currentTimeMillis()
严格根据UTC返回时间。如果您的输入时间戳也基于UTC,则时区是不相关的在这种情况下,
millis
是什么?(我怀疑这是
剩余时间
值,在这种情况下,所有这些都是有意义的,因为它代表了一个又一个历元的时间,大约是1970年1月1日00:15左右,当时马拉西亚的时区不是gmt+8。->不要使用日历显示时差)不要使用日历进行比较timestamps@njzk2我不知道,主要答案是用代码更新的,所以你可以看到我没有使用日历来比较任何东西,只是为了得到人类可读的文本。
Instant instantLater = Instant.ofEpochMilli ( Long.valueOf ( input ) );
Duration duration = Duration.between ( instantNow , instantLater );

System.out.println ( "instantNow: " + instantNow + " | instantLater: " + instantLater + " | duration: " + duration );
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 );