时区偏移不是固定的
问题来源是修复这个bug,Shanghai时区的日期问题
如果我们预先计算好8个小时的话,那么对于1900年之前的日期,seconds会少计算了343s. 我当时不是特别理解这个问题,所以就直接+343s进行了修正。这个情况对于shanghai时区没有问题,但是对于其他时区就不行了。
我的同事在review里面推荐我看两个帖子:
- java 1900年_JDK与1900年01月01日_weixin_39747049的博客-CSDN博客
- go - Why does the time package have different behaviors when date is before 1900? - Stack Overflow
大致意思就是说,Shanghai在1901-01-01 12:00:00 这个时间点上往回调整了343s. 所以在这个时间点之前的second其实就是减少343s的,但是我们在处理日期转换的时候需要考虑回来,不能直接+8处理完事。
Daylight Saving Time Changes 1900 in Shanghai, Shanghai Municipality, China
所以处理offset的时候,其实还需要传入second绝对值,才能知道具体如何调整。
C++程序可以参考下面的,需要google cctz实现 google/cctz: CCTZ is a C++ library for translating between absolute and civil times using the rules of a time zone.
void TimestampValue::from_unixtime(int64_t second, const cctz::time_zone& ctz) { static const cctz::time_point<cctz::sys_seconds> epoch = std::chrono::time_point_cast<cctz::sys_seconds>(std::chrono::system_clock::from_time_t(0)); cctz::time_point<cctz::sys_seconds> t = epoch + cctz::seconds(second); const auto tp = cctz::convert(t, ctz); from_timestamp(tp.year(), tp.month(), tp.day(), tp.hour(), tp.minute(), tp.second(), 0); }
Java程序可以参考下面额:
package com.starrocks.lab; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.util.ArrayList; import java.util.List; /* 1900-01-01 00:00:00 ---> -2209017943000000 1910-01-01 00:00:00 ---> -1893484800000000 1920-01-01 00:00:00 ---> -1577952000000000 1930-01-01 00:00:00 ---> -1262332800000000 1940-01-01 00:00:00 ---> -946800000000000 1950-01-01 00:00:00 ---> -631180800000000 1960-01-01 00:00:00 ---> -315648000000000 1970-01-01 00:00:00 ---> -28800000000 1980-01-01 00:00:00 ---> 315504000000000 1990-01-01 00:00:00 ---> 631123200000000 */ public class TimezoneOffsetTest { public static void main(String[] args) { List<Long> list = new ArrayList<>(); list.add(-2209017943L); list.add(-1893484800L); list.add(-1577952000L); list.add(-1262332800L); list.add(-946800000L); list.add(-631180800L); list.add(-315648000L); list.add(-28800L); list.add(315504000L); list.add(631123200L); DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); builder.append(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); DateTimeFormatter formatter = builder.toFormatter(); ZoneId zone = ZoneId.of("Asia/Shanghai"); for (Long sec : list) { LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochSecond(sec, 0), zone); System.out.printf("sec = %d, date = %s\n", sec, dt.format(formatter)); } } }