找出时区偏移量

9
我希望您能使用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是本地时间,所以我需要转换该时间戳以使其与本地时间匹配。
或者我完全错过了什么?

也许我在这里给出的答案会对你有所帮助。链接 - Mike V.
谢谢您的评论。我也考虑过了,但是我不想假设dst是+1小时,因为根据您提供的链接,有些国家可能会有30分钟的差异。 - Javier Mr
@JavierMr - 这个 答案中计算 zone_diff(以秒为单位)的方法确实是错误的。现在已经修正了。 - Egor Skriptunoff
2个回答

4
手册 中所述,不应直接使用 os.time() 的结果,因为它可能是任何值。应该使用 os.date() 来获取一些有意义的信息。
它只在一些系统中具有已知的含义,并且即使在这些系统中,它也仅被定义为从某个日期开始的秒数。
话虽如此,你遇到问题的原因似乎是你的表格设置了一个 isdst 标记。这意味着 os.time() 将自动从中减去一小时,因此你回到了冬令时。
顺便说一句,你最后的方法也有问题,因为在午夜之前的几个小时里,一个时间戳已经进入了下一天,所以小时字段的差异不再有效。
做到这一点的正确方法其实非常简单:
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

Lua 5.3.6,Windows 10:os.date('%z')返回UTC-6,美国中部时间(中央时区)的“Central Daylight Time”字符串。如何获取符号、小时和分钟? - vvkatwss vvkatwss
Lua是用C语言编写的,因此应该使用C编译器进行编译。微软的“C”编译器存在问题,不遵循C标准,因此导致Lua同样存在问题。解决方案是不要使用有问题的软件(例如使用mingw、WSL或完全放弃Windows)。 - DarkWiiPlayer
我找到了一个可以返回时区偏移的函数。http://lua-users.org/wiki/TimeZone local function get_timezone_offset(ts) local utcdate = os.date("!*t", ts) local localdate = os.date("*t", ts) localdate.isdst = false -- 这就是诀窍 return os.difftime(os.time(localdate), os.time(utcdate)) end - vvkatwss vvkatwss

1
我觉得差异来自于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"

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


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