为什么将这两次相减(在1927年)会得出奇怪的结果?
如果我运行以下程序,该程序将解析两个日期字符串,它们分别引用间隔为1秒的时间并进行比较:
public static void main(String[] args) throws ParseException {SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String str3 = "1927-12-31 23:54:07"; String str4 = "1927-12-31 23:54:08"; Date sDt3 = sf.parse(str3); Date sDt4 = sf.parse(str4); long ld3 = sDt3.getTime() /1000; long ld4 = sDt4.getTime() /1000;System.out.println(ld4-ld3);
}
输出为:
353
为什么ld4-ld3
不是1
(就像我从一秒的时间差中期望的那样),而是353
?
如果我将日期更改为1秒后的时间:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
然后ld4-ld3
将为1
。
Java版本:
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)Timezone(`TimeZone.getDefault()`):sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]Locale(Locale.getDefault()): zh_CN
#1楼
而不是转换每个日期,而是使用以下代码
long difference = (sDt4.getTime() - sDt3.getTime()) / 1000;
System.out.println(difference);
看到的结果是:
1
#2楼
正如其他人解释的那样,那里存在时间不连续性。 Asia/Shanghai
对于1927-12-31 23:54:08
有两种可能的时区偏移,但是对于1927-12-31 23:54:07
只有一种偏移。 因此,根据使用的偏移量,可能会有一秒的差异或5分53秒的差异。
偏移量的这种微小变化,而不是我们通常习惯的一小时夏令时(夏季时间),使问题变得有些模糊。
请注意,时区数据库的2013a更新将这种不连续性提前了几秒钟,但是效果仍然可以观察到。
Java 8上新的java.time
程序包使用户可以更清楚地看到它,并提供处理它的工具。 鉴于:
DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.append(DateTimeFormatter.ISO_LOCAL_DATE);
dtfb.appendLiteral(' ');
dtfb.append(DateTimeFormatter.ISO_LOCAL_TIME);
DateTimeFormatter dtf = dtfb.toFormatter();
ZoneId shanghai = ZoneId.of("Asia/Shanghai");String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08"; ZonedDateTime zdt3 = LocalDateTime.parse(str3, dtf).atZone(shanghai);
ZonedDateTime zdt4 = LocalDateTime.parse(str4, dtf).atZone(shanghai);Duration durationAtEarlierOffset = Duration.between(zdt3.withEarlierOffsetAtOverlap(), zdt4.withEarlierOffsetAtOverlap());Duration durationAtLaterOffset = Duration.between(zdt3.withLaterOffsetAtOverlap(), zdt4.withLaterOffsetAtOverlap());
然后, durationAtEarlierOffset
将为一秒,而durationAtLaterOffset
将为五分钟53秒。
而且,这两个偏移量是相同的:
// Both have offsets +08:05:52
ZoneOffset zo3Earlier = zdt3.withEarlierOffsetAtOverlap().getOffset();
ZoneOffset zo3Later = zdt3.withLaterOffsetAtOverlap().getOffset();
但是这两个是不同的:
// +08:05:52
ZoneOffset zo4Earlier = zdt4.withEarlierOffsetAtOverlap().getOffset();// +08:00
ZoneOffset zo4Later = zdt4.withLaterOffsetAtOverlap().getOffset();
与1927-12-31 23:59:59
和1928-01-01 00:00:00
,您会看到相同的问题,但是,在这种情况下,是较早的偏移量会产生较长的差异,而正是有两个可能的偏移量的较早日期。
解决此问题的另一种方法是检查是否正在进行过渡。 我们可以这样做:
// Null
ZoneOffsetTransition zot3 = shanghai.getRules().getTransition(ld3.toLocalDateTime);// An overlap transition
ZoneOffsetTransition zot4 = shanghai.getRules().getTransition(ld3.toLocalDateTime);
您可以使用isOverlap()
检查过渡是否是重叠的(在这种情况下,该日期/时间有多个有效偏移量)或间隔(在这种情况下,日期/时间对那个区域ID无效isOverlap()
和isGap()
上的方法zot4
。
我希望这可以帮助人们在Java 8广泛可用之后,或者对于那些采用JSR 310反向移植的使用Java 7的人们,解决此类问题。
#3楼
我很抱歉地说,但是时间的不连续性有所改变
两年前的JDK 6 ,以及最近在更新25中的JDK 7 。
要学习的经验:不惜一切代价避免非UTC时间,但可能不作展示。
#4楼
恕我直言,Java中普遍存在的隐式本地化是其最大的设计缺陷。 它可能是为用户界面设计的,但是坦率地说,今天的人真正将Java用于用户界面,除了一些IDE之外,您基本上可以忽略本地化,因为程序员并不完全是本地化的。 您可以通过以下方式修复(尤其是在Linux服务器上):
- 出口LC_ALL = C TZ = UTC
- 将系统时钟设置为UTC
- 除非绝对必要,否则不要使用本地化的实现(即仅用于显示)
我向Java Community Process成员推荐:
- 使本地化方法不是默认方法,但是要求用户显式请求本地化。
- 请改用UTF-8 / UTC作为FIXED默认值,因为这只是今天的默认值。 除了要生成这样的线程外,没有其他理由。
我的意思是,来吧,全局静态变量不是反OO模式吗? 没有什么是一些基本的环境变量给出的普遍默认值。
#5楼
就像其他人所说的,这是1927年在上海的时间更改。
基本上是上海当地时间23:54:07
,然后过了一会儿又转到第二天的00:00:00
。 但随后在当地标准时间切换回23:54:08
。 因此,这就是为什么时差为343秒而不是1秒的原因。
这也可能与美国等其他地方搞混。 在美国,他们有夏令时。 夏令时开始时,时间会提前1个小时。 但是过了一会儿,夏令时结束了,它向后退了1个小时回到标准时区。 因此有时在美国比较时间时,差异约为3600
秒而不是1秒。
最好在时间不改变的情况下使用UTC,除非需要使用非UTC时间(如在显示中)。
#6楼
import java.util.TimeZone;public class Demo {public static void main(String[] args) throws Exception {long startOf1900Utc = -2208988800000L;for (String id : TimeZone.getAvailableIDs()) {TimeZone zone = TimeZone.getTimeZone(id);if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {System.out.println(id);}}}
}
#7楼
这是12月31日在上海的时区更改。
有关1927年上海的详细信息,请参见此页 。 基本上在1927年底的午夜,时钟回到了5分52秒。 因此,“ 1927-12-31 23:54:08”实际上发生了两次,看起来Java正在将其解析为该本地日期/时间的稍后可能时刻,因此有所不同。
在时区通常又怪异而精彩的世界中,又是另一集。
编辑:停止按! 历史发生变化...
如果使用TZDB的2013a版本进行重建,原始问题将不再表现出完全相同的行为。 在2013a中,结果为358秒,转换时间为23:54:03,而不是23:54:08。
我之所以注意到这一点,是因为我在Noda Time以单元测试的形式收集了类似的问题……测试现已更改,但这只是显示出来-甚至历史数据也不安全。
编辑:历史再次改变了...
在TZDB 2014f中,更改时间已移至1900-12-31,现在仅更改了343秒(因此,如果您明白我的意思,那么t
和t+1
之间的时间为344秒)。
编辑:要回答有关1900年过渡的问题...似乎Java时区实现将所有时区都视为在1900 UTC开始之前的任何时刻都处于其标准时间:
import java.util.TimeZone;public class Test {public static void main(String[] args) throws Exception {long startOf1900Utc = -2208988800000L;for (String id : TimeZone.getAvailableIDs()) {TimeZone zone = TimeZone.getTimeZone(id);if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {System.out.println(id);}}}
}
上面的代码在Windows计算机上不产生任何输出。 因此,任何在1900年初具有除标准偏移量之外的偏移量的时区都将被视为过渡。 TZDB本身具有一些早于此的数据,并且不依赖于任何“固定的”标准时间(这是getRawOffset
认为是有效的概念)的概念,因此其他库不需要引入这种人为的转换。
#8楼
您遇到了当地时间不连续性 :
当当地标准时间即将到达星期日1月1日。将1928年1月00:00:00的时钟向后调0:05:52小时到31.星期六。1927年12月,将当地标准时间改为23:54:08
这并不是特别奇怪,并且由于政治或行政行为而更改或更改了时区,一次或多次发生在各地。
#9楼
这种奇怪的寓意是:
- 尽可能在UTC中使用日期和时间。
- 如果您无法使用UTC显示日期或时间,请始终指示时区。
- 如果您不能要求使用UTC输入日期/时间,则需要一个明确指示的时区。
#10楼
增加时间时,应转换回UTC,然后加或减。 仅将本地时间用于显示。
这样,您将可以度过数小时或数分钟两次的任何时期。
如果您转换为UTC,则每秒添加一次,然后转换为本地时间进行显示。 您将经历LMT的 11:54:08 pm-LMT的11:59:59 pm,然后经历CST的 11:54:08 pm- CST的 11:59:59 pm。
为什么将这两次相减(在1927年)会得出奇怪的结果?相关推荐
- 两种方法求解 正数数组中 两个数相减 的最大值
一,问题描述 给定一个正数数组arr(即数组元素全是正数),找出该数组中,两个元素相减的最大值,其中被减数的下标不小于减数的下标. 即求出: maxValue = max{arr[j]-arr[i] ...
- “数学黑洞”:任意一个4位自然数,将组成该数的各位数字重新排列,形成一个最大数和一个最小数,之后两数相减,其差仍为一个自然数。重复进行上述运算,最终会出现一个神秘的数,请编程输出这个神秘的数。
"数学黑洞":任意一个各位不相等的4位自然数,将组成该数的各位数字重新排列,形成一个最大数和一个最小数,之后两数相减,其差仍为一个自然数.重复进行上述运算,最终会出现一个神秘的数, ...
- 让微积分穿梭于工作与学习之间(31):无穷-无穷,两根式相减的求解套路
这篇的内容无异于上学时大家做到吐血的数学习题,此处插播一篇纯习题的文章,仅为后续的一个应用打下基础. 在微积分课程介绍极限的章节中,教材会给出无穷-无穷&两根式相减这一类极限的例子,并给出利用 ...
- js 两数相减得到精确的减法结果 减法函数
下面原因是这样的造成的,在计算运费的时候两数相减会有误差,这在js中是常见的,为解决以下问题可以写的函数方便解决问题 1.5 - 1.2 = 0.30000000000000004 解决之后的 uti ...
- 类型两个数相减_小学数学简便计算12种分类+5种易错类型,打印出来给孩子练习!(可打印!)...
简便计算对于小学生来说是个难点,也是最容易出现错误的题型. 简便计算题型 1.同种运算想交换律和结合律:交换就是为了结合. 2.有乘有加(或有减)有相同数,要想乘法分配律,无相同数找倍数关系变相同数用 ...
- es查询两列相减大于某个值的数据_南京师范大学汇编语言期末试卷
(2)变量BUF,大小为25个字节,初值为0 (3)变量ARRAY,类型为字,初值为12H,56H,78H,0AH (4)变量MSG存储字符串'yes' 答:DATA_SEG SEGMENT DB 5 ...
- 两个绝对值相减求最值_matlab同一矩阵任意两列相减绝对值的最大值和最小值
展开全部 b = [1,2,10,4,5;6,7,8,9,10;11,8,13,14,15;16,17,20,19,20]; % 求出两两相减的列索引 ic = perms(1:5); ic = ic ...
- java处理1927 12 31_java - 为什么将这两次相减(在1927年)会得出奇怪的结果? - 堆栈内存溢出...
正如其他人解释的那样,那里存在时间不连续性. Asia/Shanghai对于1927-12-31 23:54:08有两种可能的时区偏移,但是对于1927-12-31 23:54:07只有一种偏移. 因 ...
- es查询两列相减大于某个值的数据_elasticsearch 高级查询
高级查询 子条件查询 (特定字段查询所指特定值) 复合条件查询 (以一定的逻辑组合子条件查询) 一.子条件查询 子条件查询分为 query context.filter context 1.query ...
最新文章
- 盘点2015年数据中心领域十大SDN市场领导者
- 计算机里面的百度云怎么弄消失,我换了个手机登录我的百度网盘,里面存的东西都不见了,谁能告诉我怎么弄回来么...
- [有限元] 面积坐标的幂函数在三角形单元,三角形环单元上的积分公式和体积坐标的幂函数在常应变四面体单元上的积分公式
- React简单聊聊【面试】
- iMX8 Android SDK 下载
- FishC笔记—16 讲 序列,序列
- Python 脚本查询 ip纯真数据库
- 威金Worm.Viking病毒分析及处理
- dzz云桌面1.2部分主要功能图文介绍
- Android移动应用开发学习——实现简单新闻APP
- 一次性计时器和间隔性计时器的实现
- 【JAVA学习路径 表述(超级详细的Java知识宇宙)】
- java 大量数据返回_怎么接收第三方接口返回的大量数据?
- 目前市场上主流的BI产品主要有哪些?
- Android禁止截屏
- BUUCTF 九连环
- 网络协议(十四):WebSocket、WebService、RESTful、IPv6、网络爬虫、HTTP缓存
- 常用ACM知识点清单(未完待续)
- python抓取直播源 并更新_M3U8直播源有效性验证Python版
- 手机也可以轻松码代码!两款手机端代码最佳神器Pydroid和Pythonista!