Java时区转换的含义是什么?

5

我住在委内瑞拉,过去10年我们经历了两次GMT变更。

这段代码是在Java 7更新76中运行的。

System.out.println(TimeZone.getTimeZone("America/Caracas"));

打印哪些内容

sun.util.calendar.ZoneInfo[id="America/Caracas",offset=-16200000,dstSavings=0,useDaylight=false,transitions=5,lastRule=null]

当然,在2016年底,我们有了最新的更改:使用最新版本的JDK Java 8 Update 121。

sun.util.calendar.ZoneInfo[id="America/Caracas",offset=-14400000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null]

我想知道文档中所说的过渡是什么意思。 不能使用自定义时区ID指定夏令时转换计划 但是在委内瑞拉,不进行夏令时调整,我想知道这种特殊情况下的过渡是什么意思?是否意味着历史上GMT的总变化量或其他原因?

一般来说,我们使用“转换”这个词来描述当本地的“墙上时间”出现不连续性时。无论不连续性是向前还是向后移动的,或者是由于夏令时或标准时间的改变引起的,都没有关系。它只是某些操作被执行以修改本地时钟的点。您会在所有技术平台和技术之外的时间保持中找到这个术语。 - Matt Johnson-Pint
2个回答

5

ZoneInfotransitions字段有以下注释:

该数组描述了此时区的GMT偏移量转换,包括原始偏移量更改和夏令时更改。一个长整数由四个位字段组成。

虽然委内瑞拉没有夏令时,但是它的GMT偏移量确实发生了一些变化。使用Linux命令zdump -v America/Caracas,您会得到以下输出:

America/Caracas  -9223372036854775808 = NULL
America/Caracas  -9223372036854689408 = NULL
America/Caracas  Wed Jan  1 04:27:43 1890 UT = Tue Dec 31 23:59:59 1889 LMT isdst=0 gmtoff=-16064
America/Caracas  Wed Jan  1 04:27:44 1890 UT = Wed Jan  1 00:00:04 1890 CMT isdst=0 gmtoff=-16060
America/Caracas  Mon Feb 12 04:27:39 1912 UT = Sun Feb 11 23:59:59 1912 CMT isdst=0 gmtoff=-16060
America/Caracas  Mon Feb 12 04:27:40 1912 UT = Sun Feb 11 23:57:40 1912 VET isdst=0 gmtoff=-16200
America/Caracas  Fri Jan  1 04:29:59 1965 UT = Thu Dec 31 23:59:59 1964 VET isdst=0 gmtoff=-16200
America/Caracas  Fri Jan  1 04:30:00 1965 UT = Fri Jan  1 00:30:00 1965 VET isdst=0 gmtoff=-14400
America/Caracas  Sun Dec  9 06:59:59 2007 UT = Sun Dec  9 02:59:59 2007 VET isdst=0 gmtoff=-14400
America/Caracas  Sun Dec  9 07:00:00 2007 UT = Sun Dec  9 02:30:00 2007 VET isdst=0 gmtoff=-16200
America/Caracas  Sun May  1 06:59:59 2016 UT = Sun May  1 02:29:59 2016 VET isdst=0 gmtoff=-16200
America/Caracas  Sun May  1 07:00:00 2016 UT = Sun May  1 03:00:00 2016 VET isdst=0 gmtoff=-14400
America/Caracas  9223372036854689407 = NULL
America/Caracas  9223372036854775807 = NULL

请注意右侧的gmtoff列。 每对行代表一个转换。 您可以看到有更多的转换,早在10年前。

实际上,Java做法略有不同。 它仅记录自1900年以来的转换,因此不包括1890年的偏移量。 但是它会在未来添加一个虚拟转换。 您可以使用以下代码(Java 8)查看实际转换:

import java.lang.reflect.Field;
import java.time.Instant;
import java.util.TimeZone;

public class SimpleTest {

    public static void main(String[] args) {
        TimeZone tz = TimeZone.getTimeZone("America/Caracas");

        Field f = null;
        try {
            f = tz.getClass().getDeclaredField("transitions");
            f.setAccessible(true);
            long[] transitions = (long[]) f.get(tz);
            f = tz.getClass().getDeclaredField("offsets");
            f.setAccessible(true);
            int[] offsets = (int[]) f.get(tz);

            for ( long transition : transitions ) {
                Instant transitionInstant = Instant.ofEpochMilli(transition >> 12);
                int offset = offsets[(int)transition & 0xF];
                System.out.println( transitionInstant + " : " + offset);
            }
        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

输出结果如下:
1900-01-01T00:00:00Z : -16060000
1912-02-12T04:27:40Z : -16200000
1965-01-01T04:30:00Z : -14400000
2007-12-09T07:00:00Z : -16200000
2016-05-01T07:00:00Z : -14400000
2037-01-01T04:00:00Z : -14400000

很好,但这意味着什么,我的朋友。美国/加拉加斯2007年12月9日星期日06:59:59 UT = 2007年12月9日星期日02:59:59 VET isdst = 0 gmtoff = -14400。美国/加拉加斯2007年12月9日星期日07:00:00 UT = 2007年12月9日星期日02:30:00 VET isdst = 0 gmtoff = -16200只有一秒钟? - chiperortiz
@chiperortiz 在zdump输出中,每一对行代表一个转换 - 偏移之前和偏移之后,因此第二个的差异。Java处理方式略有不同。我只包含了zdump输出,以向您展示过去有更多的转换。 - RealSkeptic

1

转换是一个数组,你只能得到它的长度(在这种情况下为6)

我引用:

该数组描述了此时区的GMT偏移的转换,包括原始偏移更改和夏令时更改。长整数由四个位字段组成。最高有效52位字段表示从公历1970年1月1日00:00:00 GMT起的毫秒转换时间。下一个4位字段保留,必须为0。下一个4位字段是offsets[]的索引值,用于转换时的夏令时量。如果该值为零,则表示没有夏令时,而不是索引值为零。最低有效4位字段是offsets[]的索引值,用于转换时的总GMT偏移。如果此时区不遵循夏令时并且过去从未更改过任何GMT偏移,则此值为空。

这里是source


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接