timezone用法 - java默认时区




为什么减去这两次(在1927年)给出一个奇怪的结果? (6)

如果我运行以下程序,它解析引用时间间隔为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 (正如我所预期的那样,时间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

增加时间时,您应该转换回UTC然后加或减。 仅使用当地时间进行显示。

通过这种方式,您可以在几小时或几分钟发生两次的任何时段走过。

如果您转换为UTC,请添加每秒,然后转换为本地时间进行显示。 你可以通过下午11:54:08 LMT - 美国中部时间晚上11:59:59和美国中部时间晚上11:59:59。


恕我直言,Java中普遍存在的隐式本地化是其最大的单一设计缺陷。 它可能适用于用户界面,但坦率地说,今天谁真正使用Java作为用户界面,除了一些IDE,你基本上可以忽略本地化,因为程序员并不完全是它的目标受众。 您可以通过以下方式修复它(特别是在Linux服务器上):

  • export LC_ALL = C TZ = UTC
  • 将系统时钟设置为UTC
  • 除非绝对必要,否则永远不要使用本地化的实现

对于Java Community Process成员,我建议:

  • 使本地化方法不是默认方法,但要求用户明确请求本地化。
  • 使用UTF-8 / UTC作为FIXED默认值,因为这只是今天的默认值。 除非您想生成这样的线程,否则没有理由做其他事情。

我的意思是,来吧,不是全局静态变量是反OO模式吗? 没有其他东西是由一些基本环境变量给出的普遍违约.......


您遇到了当地时间不连续

当地标准时间即将到达星期日时,1928年1月1日00:00:00时钟倒退0:05:52到星期六,31。1927年12月31日,当地标准时间23:54:08

这并不是特别奇怪,并且由于政治或行政行为导致时区被切换或改变,因此在任何时候都发生过这种情况。


我很遗憾地说,但是时间的不连续性已经发生了变化

两年前的JDK 6 ,以及最近在更新25中的JDK 7

需要学习的经验:不惜一切代价避免非UTC时间,可能用于显示。


这是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的形式收集这样的问题......测试现在已经改变了,但它只是显示 - 甚至历史数据都不安全。

编辑:历史再次发生变化......

在TZDB 2014f中,更改的时间已经变为1900-12-31,现在只有343秒的变化(所以tt+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假定为有效概念),因此其他库不需要引入这种人工转换。


这种陌生感的道德是:

  • 尽可能使用UTC中的日期和时间。
  • 如果您无法以UTC格式显示日期或时间,请始终指明时区。
  • 如果您不能要求以UTC格式输入日期/时间,则需要明确指定的时区。




timezone