Javier Mr
Javier Mr

Reputation: 2210

Find out timezone offset

I wish to find the timezone offset using Lua, however I'm facing what looks odd behaviour, so I must be missing something.

I'm using the code:

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 );

Which produces the output:

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

Now I'm located in UTC+2 (currently due to summer time, in winter is UTC+1, CEST) so I expected to see an offset of 7200 seconds. However the first two attempts, which should be equivalent, and they are; give me a difference of only one hour. When printing the time in human readable format it can clearly be seen that the offset between both are 2 hours. The fourth attempt is using a fixed point in time (86400 number of seconds in a day, technique from this question) the offset is also 1 hour). Finally when directly subtracting directly the hours (and minutes just in case of not whole hours offset) I get the 2 hours offset.

I suspect this is due to the daylight saving time or dst. What I'm trying to accomplish is get the time from a timestamp (already in UTC), and since os.time is in local time I need to convert that timestamp so it matches localtime.

Or am I completely missing something?

Upvotes: 9

Views: 1897

Answers (2)

DarkWiiPlayer
DarkWiiPlayer

Reputation: 7064

As stated in the manual, you shouldn't use the result of os.time() directly, because it can be any value. Use os.date() to get some meaningful information out of it.

It only has any known meaning at all in a few systems, and even then it's only defined that it's a number of seconds since some date.

That being said, the reason you're having this problem seems to be the fact that your table has an isdst flag set. This means os.time() will automatically subtract an hour from it, so you're back to winter time.

Your last aproach is bugged too, by the way, since it won't work in the hours before midnight, where one timestamp is already in the next day, so the difference of the hour fields doesn't work anymore.

The correct way of doing this is surprisingly easy:

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))

Which prints:

+     02    00
7200  number

Upvotes: 4

Lorinc Nyitrai
Lorinc Nyitrai

Reputation: 960

I think the discrepancy comes from how os.time() reads the table created by os.date('*t'), espacially its isdst (is daylight saving time) field.

Consider this example:

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"

I'm sorry if I'm stating the obvious, though.

Upvotes: 1

Related Questions