os.time() and timezones

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

os.time() and timezones

Rena
It looks like in 5.1, os.date() can be told to give times in GMT, but
os.time(), given a table, always returns the result in the local
timezone. It also appears there's no easy way to check what the
current timezone offset is. (The best I can see would be some magic
involving os.date('%z') which then also has to be corrected for DST.
Ouch.) Does Lua provide a way to turn a table into a Unix timestamp
under the assumption that the table specifies GMT, not the local
timezone?

--
Sent from my toaster.

Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

steve donovan
On Fri, Apr 13, 2012 at 10:16 AM, Rena <[hidden email]> wrote:
> Ouch.) Does Lua provide a way to turn a table into a Unix timestamp
> under the assumption that the table specifies GMT, not the local
> timezone?

I use this kind of logic to find the timezone offset in pl.Date:

        local t = os.time()
        local ut = os.date('!*t',t)
        local lt = os.date('*t',t)
        thour = lt.hour - ut.hour
        tmin = lt.min - ut.min

If this is misguided I would certainly like to know!

steve d.

Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

Tony Finch
In reply to this post by Rena
Rena <[hidden email]> wrote:

> It looks like in 5.1, os.date() can be told to give times in GMT, but
> os.time(), given a table, always returns the result in the local
> timezone.

This is because of a limitation in the standard C library. There are
struct tm *localtime(time_t) and struct tm *gmtime(time_t) for unpacking
times, but only time_t mktime(struct tm *) for repacking them. The missing
function time_t timegm(struct tm *) is provided by good unixes but is not
part of the standard C library nor even in POSIX!

> It also appears there's no easy way to check what the current timezone
> offset is.

Good unixes extend struct tm with a tm_gmtoff field, but again this
feature is not in the standards.

Steve Donovan has described a suitable workaround for you.

Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
Fair Isle, Faeroes: Northeasterly backing northerly 5 or 6, occasionally 7 at
first in southeast Fair Isle. Moderate or rough. Wintry showers. Good,
occasionally poor.

Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

Sean Conner
In reply to this post by steve donovan
It was thus said that the Great steve donovan once stated:
> On Fri, Apr 13, 2012 at 10:16 AM, Rena <[hidden email]> wrote:
> > Ouch.) Does Lua provide a way to turn a table into a Unix timestamp
> > under the assumption that the table specifies GMT, not the local
> > timezone?

  Even operating systems have trouble with timezones:

http://www.chronos-st.org/Discovering%20the%20Local%20Time%20Zone--Why%20It%27s%20a%20Hard%20Problem.html

> I use this kind of logic to find the timezone offset in pl.Date:
>
>         local t = os.time()
>         local ut = os.date('!*t',t)
>         local lt = os.date('*t',t)
>         thour = lt.hour - ut.hour
>         tmin = lt.min - ut.min
>
> If this is misguided I would certainly like to know!

  It is.  Try this:

gmt = {  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 , 10 , 11 ,
        12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 }
loc = { 19 , 20 , 21 , 22 , 23 ,  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,
         7 ,  8 ,  9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 }

for i = 1 , 24 do
  print(i,loc[i] - gmt[i])
end

And even when it does work, it still doesn't take into account DST.  I found
this works:

now   = os.time()
lmt   = os.date("*t",now)
gmt   = os.date("!*t",now)
timel = os.time(lmt)
timeg = os.time(gmt)
zone  = os.difftime(timel,timeg)

if lmt.isdst then
  if zone < 0 then
    zone = zone + 3600
  else
    zone = zone - 3600
  end
end

  -spc (Time is hard!  I wonder how The Doctor does it?)


Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

Daurnimator
On 14 April 2012 06:26, Sean Conner <[hidden email]> wrote:

>  Even operating systems have trouble with timezones:
>
> http://www.chronos-st.org/Discovering%20the%20Local%20Time%20Zone--Why%20It%27s%20a%20Hard%20Problem.html
>
>> I use this kind of logic to find the timezone offset in pl.Date:
>>
>>         local t = os.time()
>>         local ut = os.date('!*t',t)
>>         local lt = os.date('*t',t)
>>         thour = lt.hour - ut.hour
>>         tmin = lt.min - ut.min
>>
>> If this is misguided I would certainly like to know!
>
>  It is.  Try this:
>
> gmt = {  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 , 10 , 11 ,
>        12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 }
> loc = { 19 , 20 , 21 , 22 , 23 ,  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,
>         7 ,  8 ,  9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 }
>
> for i = 1 , 24 do
>  print(i,loc[i] - gmt[i])
> end
>
> And even when it does work, it still doesn't take into account DST.  I found
> this works:
>
> now   = os.time()
> lmt   = os.date("*t",now)
> gmt   = os.date("!*t",now)
> timel = os.time(lmt)
> timeg = os.time(gmt)
> zone  = os.difftime(timel,timeg)
>
> if lmt.isdst then
>  if zone < 0 then
>    zone = zone + 3600
>  else
>    zone = zone - 3600
>  end
> end
>
>  -spc (Time is hard!  I wonder how The Doctor does it?)
>
>

And now you're assuming daylight savings is for an hour.
Also that timezones are only on the hour.

eg; see Lord Howe island in Australia: LHDT/LHST

Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

Rena
In reply to this post by Sean Conner
On Fri, Apr 13, 2012 at 14:26, Sean Conner <[hidden email]> wrote:

> It was thus said that the Great steve donovan once stated:
>> On Fri, Apr 13, 2012 at 10:16 AM, Rena <[hidden email]> wrote:
>> > Ouch.) Does Lua provide a way to turn a table into a Unix timestamp
>> > under the assumption that the table specifies GMT, not the local
>> > timezone?
>
>  Even operating systems have trouble with timezones:
>
> http://www.chronos-st.org/Discovering%20the%20Local%20Time%20Zone--Why%20It%27s%20a%20Hard%20Problem.html
>
>> I use this kind of logic to find the timezone offset in pl.Date:
>>
>>         local t = os.time()
>>         local ut = os.date('!*t',t)
>>         local lt = os.date('*t',t)
>>         thour = lt.hour - ut.hour
>>         tmin = lt.min - ut.min
>>
>> If this is misguided I would certainly like to know!
>
>  It is.  Try this:
>
> gmt = {  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 , 10 , 11 ,
>        12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 }
> loc = { 19 , 20 , 21 , 22 , 23 ,  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,
>         7 ,  8 ,  9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 }
>
> for i = 1 , 24 do
>  print(i,loc[i] - gmt[i])
> end
>
> And even when it does work, it still doesn't take into account DST.  I found
> this works:
>
> now   = os.time()
> lmt   = os.date("*t",now)
> gmt   = os.date("!*t",now)
> timel = os.time(lmt)
> timeg = os.time(gmt)
> zone  = os.difftime(timel,timeg)
>
> if lmt.isdst then
>  if zone < 0 then
>    zone = zone + 3600
>  else
>    zone = zone - 3600
>  end
> end
>
>  -spc (Time is hard!  I wonder how The Doctor does it?)
>
>

Hmm, are you sure about that DST correction? Perhaps I'm not parsing
HTTP dates properly:
function rena_http.parse_date(date)
        local month_names = { jan=1, feb=2, mar=3, apr=4,  may=5, jun=6, jul=7,
                aug=8, sep=9, oct=10, nov=11, dec=12}
        local day, mon, year, hour, min, sec = date:match(
                '...,? (%d-) (...) (%d-) (%d-):(%d-):(%d-)')

        month = month_names[mon and mon:lower()]
        if not (year and month and day and hour and min and sec) then return nil end
        local ok, res = pcall(os.time,
                {year=year, month=month, day=day, hour=hour, min=min, sec=sec})
        return ok and res or nil
end

I send a last-modified date of: Wed, 12 Jan 2011 08:22:15 GMT
which I get from os.date('!%a, %d %b %Y %H:%M:%S GMT', 1294820535)
Firefox subsequently sends the same date in an If-Modified-Since
header, but the above code parses it to a timestamp 7 hours behind the
current time, which I assume must be because of os.time() assuming the
table is local time. The local timezone is actually -0600 but I guess
DST accounts for the extra hour. But Sean's code only gives the
correct offset if I remove the "if lmt.isdst" check...

(man, whose idea was it to use local, human-readable dates for HTTP? I
at least send out X-Unix-Time and X-Lastmodified-Unix headers, just a
shame the browsers don't do the same...)

--
Sent from my toaster.

Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

Sean Conner
It was thus said that the Great Rena once stated:

> On Fri, Apr 13, 2012 at 14:26, Sean Conner <[hidden email]> wrote:
> > It was thus said that the Great steve donovan once stated:
> >> On Fri, Apr 13, 2012 at 10:16 AM, Rena <[hidden email]> wrote:
> >> > Ouch.) Does Lua provide a way to turn a table into a Unix timestamp
> >> > under the assumption that the table specifies GMT, not the local
> >> > timezone?
> >
> >  Even operating systems have trouble with timezones:
> >
> > http://www.chronos-st.org/Discovering%20the%20Local%20Time%20Zone--Why%20It%27s%20a%20Hard%20Problem.html
> >
> >> I use this kind of logic to find the timezone offset in pl.Date:
> >>
> >>         local t = os.time()
> >>         local ut = os.date('!*t',t)
> >>         local lt = os.date('*t',t)
> >>         thour = lt.hour - ut.hour
> >>         tmin = lt.min - ut.min
> >>
> >> If this is misguided I would certainly like to know!
> >
> >  It is.  Try this:
> >
> > gmt = {  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 , 10 , 11 ,
> >        12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 }
> > loc = { 19 , 20 , 21 , 22 , 23 ,  0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,
> >         7 ,  8 ,  9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 }
> >
> > for i = 1 , 24 do
> >  print(i,loc[i] - gmt[i])
> > end
> >
> > And even when it does work, it still doesn't take into account DST.  I found
> > this works:
> >
> > now   = os.time()
> > lmt   = os.date("*t",now)
> > gmt   = os.date("!*t",now)
> > timel = os.time(lmt)
> > timeg = os.time(gmt)
> > zone  = os.difftime(timel,timeg)
> >
> > if lmt.isdst then
> >  if zone < 0 then
> >    zone = zone + 3600
> >  else
> >    zone = zone - 3600
> >  end
> > end
> >
> >  -spc (Time is hard!  I wonder how The Doctor does it?)
> >
> >
>
> Hmm, are you sure about that DST correction?

  Actually, I'm wrong [1].  It should be:

        if lmt.isdst then
          zone = zone + 3600
        end

Man, this stuff is nasty.

  -spc (Needs to spend more time testing ... )

[1] Yes, I know---I'm not taking into account time zones that aren't an
        hour long.

Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

Geoff Leyland
In reply to this post by Rena
On 13/04/2012, at 8:16 PM, Rena wrote:

> It looks like in 5.1, os.date() can be told to give times in GMT, but
> os.time(), given a table, always returns the result in the local
> timezone. It also appears there's no easy way to check what the
> current timezone offset is. (The best I can see would be some magic
> involving os.date('%z') which then also has to be corrected for DST.
> Ouch.) Does Lua provide a way to turn a table into a Unix timestamp
> under the assumption that the table specifies GMT, not the local
> timezone?

Does this help? http://lua-users.org/lists/lua-l/2008-03/msg00051.html

Reply | Threaded
Open this post in threaded view
|

Re: os.time() and timezones

Egil Hjelmeland
In reply to this post by Rena
Den 2012-04-13 10:16, skrev Rena:
> Does Lua provide a way to turn a table into a Unix timestamp
> under the assumption that the table specifies GMT, not the local
> timezone?
>
If you can assume unix time, the following seem to work:


local epoch =  {year=1970, month=1, day=1, hour=0, min=0, sec=0,
isdst=false }
function gmtime(t)
   t.isdst =  false
   return os.time(t) - os.time(epoch)
end


For os.time(t) I found that t.isdst=false means force 'no DST', while
t.isdst=nil means assume DST as known for that day. Perhaps a note in
the Lua reference manual would be good?

BR
egil