且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

夏令时时移班一小时

更新时间:2023-12-05 22:40:52

UTC

始终使用 UTC 进行数据交换和这种读数日志.始终,始终,始终使用UTC.将UTC视为一个真实时间,而将其他时区视为与UTC的偏差.

UTC

Always use UTC for data exchange and this kind of readings log. Always, always, always use UTC. Think of UTC as the One True Time and other time zones as deviations from UTC.

顺便说一句,夏令时(DST)不是 >分区日期时间值唯一需要担心的问题.其他异常会在各个时区发生,导致壁钟时间向前或向后移动.解决方案很简单:避免使用所有时区– 使用UTC .

By the way, Daylight Saving Time (DST) is not the only problem to worry about with zoned date-time values. Other anomalies occur in various time zones resulting in wall-clock time shifting forward or backward. The solution is easy: Avoid all time zones – Use UTC.

Instant类捕获UTC时间轴上的时刻,分辨率为纳秒.这应该是您上班的日期时间工作.

The Instant class captures a moment on the timeline in UTC with a resolution of nanoseconds. This should be you go-to class for date-time work.

Instant instant = Instant.now();

字符串

要进行记录,请生成标准 ISO 8601 格式的字符串.坚持使用经过验证的ISO 8601格式,而不要发明自己的格式.

Strings

For logging, generate a string in standard ISO 8601 format. Stick with the proven ISO 8601 formats rather than invent your own.

包括Instant在内的java.time类在解析/生成字符串时默认使用ISO 8601格式.因此,无需指定格式化模式.

The java.time classes including Instant use ISO 8601 formats by default when parsing/generating strings. So no need to specify formatting patterns.

String output = instant.toString();

2016-11-02T21:10:05.321Z

2016-11-02T21:10:05.321Z

Instant instant = Instant.parse( "2016-11-02T21:10:05.321Z" );

并且始终在您的日期中包含世纪20.遗漏只是为误解中的错误创造了很多机会.存储和内存确实足够便宜,我们可以负担两个额外的数字.

And always include the century 20 in your dates. Omitting just creates so much opportunity for errors in misinterpreting. Storage and memory really is cheap enough that we can afford the two extra digits.

始终在您的序列化日期时间值中包含时区或UTC偏移量指示符.

Always include a time zone or offset-from-UTC indicator with your serialized date-time values.

在上面看到的Instant::toString结果中,Z代表Zulu,表示UTC.

In the Instant::toString result seen above, the Z stands for Zulu which means UTC.

这里是解析您的日期时间字符串的代码.我们首先解析为 LocalDateTime 任何时区或偏移量,因为您的输入缺少任何时区或偏移量指示符.然后,我们分配一个时区以获取 ZonedDateTime ,以了解如何处理DST转换的瞬间.

Here is code to parse your date-time strings. We parse as LocalDateTime first, without any time zone or offset, because your input lacks any indicator of time zone or offset. Then we assign a time zone to get a ZonedDateTime, to see how it handles the moment of DST cut-over.

我假设您所涉及的时区使用DST后备切换时间凌晨2点.我以America/Montreal为例.

I assume your time zone in question uses a DST fall-back cutover of 2 AM. I used America/Montreal as an example of such.

List<String> inputs = new ArrayList<>( 2 );
inputs.add( "141102 0115" );  // 1 AM
inputs.add( "141102 0215" );  // 2 AM

for( String input : inputs ) {
    DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuMMdd HHmm" );
    LocalDateTime ldt = LocalDateTime.parse( input , f );

    // At 2 AM in this zone, the clock falls back one hour for DST cutover. The 1 AM hour repeats.
    ZoneId z = ZoneId.of( "America/Montreal" );
    ZonedDateTime zdt = ldt.atZone( z );

    System.out.println( "input: " + input );
    System.out.println( "ldt: " + ldt );
    System.out.println( "zdt: " + zdt );
    System.out.println( "instant: " + zdt.toInstant() );
    System.out.println("");
}

输入:141102 0115

input: 141102 0115

ldt:2014-11-02T01:15

ldt: 2014-11-02T01:15

zdt:2014-11-02T01:15-04:00 [美国/蒙特利尔]

zdt: 2014-11-02T01:15-04:00[America/Montreal]

即时:2014-11-02T05:15:00Z

instant: 2014-11-02T05:15:00Z

…和…

输入:141102 0215

input: 141102 0215

ldt:2014-11-02T02:15

ldt: 2014-11-02T02:15

zdt:2014-11-02T02:15-05:00 [美国/蒙特利尔]

zdt: 2014-11-02T02:15-05:00[America/Montreal]

即时:2014-11-02T07:15:00Z

instant: 2014-11-02T07:15:00Z

您可以在IdeOne.com中实时查看此代码.请注意UTC值(Z)的两个小时差异.

You can see this code live in IdeOne.com. Note the two hour difference in UTC values (Z).

我们看到的行为已记录在案.

The behavior we see is documented.

在大多数情况下,本地日期时间只有一个有效偏移量.在重叠的情况下,将时钟调回,则有两个有效的偏移量.此方法使用通常对应于夏季"的更早偏移量.

In most cases, there is only one valid offset for a local date-time. In the case of an overlap, where clocks are set back, there are two valid offsets. This method uses the earlier offset typically corresponding to "summer".

在1:15 AM模棱两可的情况下,可能是第一次出现,也可能是第二次出现,java.time与第一次出现一起出现.

Where the 1:15 AM is ambiguous, could be either the first or second occurrence, java.time goes with the first.

您可以玩猜谜游戏来尝试调整这些设计欠佳的琴弦.如果确定每个时钟小时内至少有一个样本,则可以跟踪先前的样本,并查看正在处理的样本的时钟时间是否早于先前的时间.如果是这样,您可以假定这是DST后备转换,并使用plusHours( 1 )添加一个小时.

You could play a guessing-game to try to adjust these poorly-designed strings. If you are sure you have at least one sample during every clock hour, you could keep track of previous samples and see if the sample being processed has a clock-time earlier than the previous. If so you could assume this is a DST fall-back cutover, and add an hour with plusHours( 1 ).

if( processingZdt.toLocalDateTime().isBefore( previousZdt.toLocalDateTime() ) { 
    processingZdt.plusHours( 1 ) ;  // A hack; I am *not* recommending this.
    …

但这是一个危险的解决方案.我不确定这项工作,因为我还没有仔细考虑.如果不顾一切,也许您可​​以使它工作.

But this is a risky hack of a solution. I'm not sure this work, as I've not thought it through. If desperate, perhaps you can make it work.

最明智的方法是预防:使用UTC .

The much wise approach is prevention: Use UTC.