Getting UTC UNIX timestamp in Lua
Asked Answered
D

3

17

An API returns a timestamp as UNIX timestamp at UTC and I would like to know if this timestamp was more than x seconds ago. As expected, this works fine with os.time() - x > timestamp in UTC, but blows up in other timezones.

Unfortunately I can't find a good way solve this in lua.

os.date helpfully has the ! prefix (e.g. os.date("!%H:%M:%S")) to return time at UTC, but it seems that despite the documentation stating it supports all strftime options, this does not support the %s option. I have heard people mention that this is caused by Lua compile time options for a similar issue, but changing these is not possible as the interpreter is provided by the user.

Defence answered 8/5, 2017 at 20:59 Comment(0)
I
18

You can use

os.time(os.date("!*t"))

to get the current UNIX epoch.

Interjection answered 8/5, 2017 at 21:10 Comment(5)
ohh that makes a lot of sense. I had tried it the other way around and I couldn't get it to do anything useful!Defence
a note on performance: This is around 500x slower than taking os.time() and subtracting the difference. However because I anticipate bugs with that approach and expect max msg/sec to be around 200 I will go with this.Defence
Glad you measured.Interjection
Actually, it fails on my system. linux date returns 14:40, date -u returns 12:40, but lua os.time(os.date("!*t")) returns 1562240400 which corresponds to 13:40, so it seems there are timezone/DST issuesXerophthalmia
os.time(os.date("*t")) works without DST issueKowloon
L
6

Ok, so you want the UTC time. Keep in mind that os.time actually knows nothing about timezones, so for example:

os.time(os.date("!*t"))  -- not UTC!
  1. Will get UTC time and populate table struct.
  2. Will convert table struct according to current timezone to unix timestamp.

So you actually would get your UNIX_TIME - TIMEZONE_OFFSET. If you are in GMT+5 you will get timestamp at UTC-5.

The correct way to do time conversion in lua is:

os.time() -- get current epoch value
os.time{ ... } -- get epoch value for local date/time values
os.date("*t"),os.date("%format") -- get your local date/time
os.date("!*t") or os.date("!%format") -- get UTC date/time
os.date("*t", timestamp),os.date("%format", timestamp) -- get your local date/time for given timestamp
os.date("!*t", timestamp) or os.date("!%format", timestamp) -- get UTC date/time for given timestamp

Kudos to Mons at https://gist.github.com/ichramm/5674287.

If you really need to convert any UTC date to timestamp, there's a good description on how to do this in this question: Convert a string date to a timestamp

Linctus answered 28/9, 2020 at 17:56 Comment(0)
B
0

os.time() gives you the unix timestamp. The timestamp is seconds since 00:00:00 UTC on 1 January 1970, so it's the same across timezones.

For example, run this code:

print('timestamp', os.time())
print('local hour', os.date("*t").hour)
print('utc hour', os.date("!*t").hour)

Presumably, your local and utc hour are different. Also run it in an online repl (make sure to re-run). The server's local and utc hour are the same, but both your and the server's timestamp are about the same.

That's why you should use os.time() to get a timezone-agnostic timestamp.

Breathing answered 25/8, 2021 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.