找出时区偏移量

我想使用 Lua 找出时区偏移量,然而我遇到了看起来很奇怪的行为,所以一定是我漏掉了什么。

我正在使用代码:

local t1 = os.time();
local t2 = os.time( os.date( "!*t" ) );
print( t1, t2, t1 - t2 );

local t1 = os.time( os.date( "*t" ) );
local t2 = os.time( os.date( "!*t" ) );
print( t1, t2, t1 - t2 );

local t1 = os.date( "%c" );
local t2 = os.date( "!%c" );
print( t1, t2 );

local t1 = os.time( os.date( "*t", 86400 ) );
local t2 = os.time( os.date( "!*t", 86400 ) );
print( t1, t2, t1 - t2 );

local t1 = os.date( "*t" );
local t2 = os.date( "!*t" );
print( t1.hour, t1.isdst, t2.hour, t2.isdst );
print( ((t1.hour - t2.hour) * 60 + (t1.min - t2.min)) * 60 );

它产生的输出为:

1496733916      1496730316      3600
1496733916      1496730316      3600
06/06/17 09:25:16       06/06/17 07:25:16
86400   82800   3600
9       true    7       false
7200

现在我在 UTC+2 时区(当前是夏令时,冬季是 UTC+1,CEST),所以我期望看到偏移量为 7200 秒。然而前两次尝试应该是等价的,它们确实是;给我一个仅相差一小时的差异。当以人类可读格式打印时间时,可以清楚地看到两者之间的偏移量为 2 小时。第四次尝试使用一个固定的时间点(一天中的 86400 秒数,来自 这个问题 的技术上的方法)偏移量也是 1 小时。最后,直接减去小时数(以及在非整小时偏移量的情况下减去分钟)得到 2 小时的偏移量。

我怀疑这是由于夏令时或 dst。我试图实现的是从时间戳(已经在 UTC 中)获取时间,并且由于 os.time 是在本地时间中,我需要将该时间戳转换为匹配本地时间。

或者我完全错过了什么?

点赞
用户1486768
用户1486768

我认为差异来自于os.time()如何读取由os.date('*t')创建的表格,特别是它的isdst(是否夏令时)字段。

考虑以下示例:

tstamp = os.date('*t')
>> {day = 24,
    hour = 10,
    isdst = true,
    min = 39,
    month = 7,
    sec = 31,
    wday = 2,
    yday = 205,
    year = 2017}

os.date('%c', os.time(tstamp))
>> "Mon Jul 24 10:39:31 2017"

tstamp.isdst = false
os.date('%c', os.time(tstamp))
>> "Mon Jul 24 11:39:31 2017"

如果我说的是显而易见的话,我很抱歉。

2017-07-24 08:49:06
用户4984564
用户4984564

手册 所述,不应直接使用 os.time() 的结果,因为它可以是任何值。使用 os.date() 以获取其中的一些有意义的信息。

在一些系统中,它仅具有少量已知的意义,并且在那些系统中它仅定义为距离某个日期的秒数。

话虽如此,你遇到的问题似乎是你的表中设置了 isdst 标志。这意味着 os.time() 将自动从中减去一小时,因此又回到了冬季时间。

顺便说一下,你最后的方法也有 bug,因为在午夜之前的几个小时,一个时间戳已经在下一天了,因此小时字段的差异不再有效。

正确的方法非常简单:

local timezone = os.date('%z') -- "+0200"
local signum, hours, minutes = timezone:match '([+-])(%d%d)(%d%d)'

print(signum, hours, minutes)

local dt = (tonumber(signum..hours)*3600 + tonumber(signum..minutes)*60)

print(dt, type(dt))

输出结果为:

+     02    00
7200  number
2019-10-18 11:57:19