如果我运行以下程序,它会解析两个引用时间相隔 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?
ld4-ld3
1
如果我将日期更改为 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
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秒,如果你明白我的意思)。
t
t+1
编辑:要回答有关 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一个有效的概念),因此其他库不需要引入这种人工转换。
getRawOffset