Javier Mr
Javier Mr

Reputation: 2210

Back and forth UTC dates in lua

I'm having problems converting a lua date to a timestamp and then obtaining back the original date from it. It does work for non UTC dates, but not with UTC.

Currently my example code is:

local dt1 = os.date( "*t" );
print( dt1.hour );

local dt2 = os.date( "*t", os.time( dt1 ) );
print( dt2.hour );

print( "-=-=-" );

local dt1 = os.date( "!*t" );
print( dt1.hour );

local dt2 = os.date( "!*t", os.time( dt1 ) );
print( dt2.hour );

local dt2 = os.date( "*t", os.time( dt1 ) );
print( dt2.hour );

Which yields the output:

12
12
-=-=-
10
9
11

So, in the second part, after obtaining the timestamp using os.time( os.date( "!*t" ) ); I don't know how to obtain the original date back. What is it that I'm doing wrong?

Upvotes: 3

Views: 3134

Answers (3)

Egor Skriptunoff
Egor Skriptunoff

Reputation: 23757

Working with "date tables" in Lua

Let dt be a "date table".
For example, a value returned by os.date("*t") is a "date table".


How to normalize "date table"
For example, after adding 1.5 hours to the current time
local dt = os.date("*t"); dt.min = dt.min + 90
you need to normalize the table fields.

function normalize_date_table(dt)
   return os.date("*t", os.time(dt))
end

This function returns new date table which is equivalent to its argument dt regardless of the meaning of content of dt: whether it contains local or GMT time.


How to convert Unix time to "local date table"

dt = os.date("*t", ux_time)

How to convert Unix time to "GMT date table"

dt = os.date("!*t", ux_time)

How to convert "local date table" to Unix time

ux_time = os.time(dt)

How to convert "GMT date table" to Unix time

-- for this conversion we need precalculated value "zone_diff"
local tmp_time = os.time()
local d1 = os.date("*t",  tmp_time)
local d2 = os.date("!*t", tmp_time)
d1.isdst = false
local zone_diff = os.difftime(os.time(d1), os.time(d2))
-- zone_diff value may be calculated only once (at the beginning of your program)

-- now we can perform the conversion (dt -> ux_time):
dt.sec = dt.sec + zone_diff
ux_time = os.time(dt)

Upvotes: 6

lhf
lhf

Reputation: 72342

You're doing nothing wrong.

Lua uses the ISO C and POSIX date and time functions. In particular, os.time uses mktime, which only interprets the input structure according to the current timezone setting in the environment variable TZ. Unfortunately, these standards do not provide a function that interprets the input structure according to GMT/UTC.

Upvotes: 1

Vyacheslav
Vyacheslav

Reputation: 27221

I found the only solution to works this date , time and time zones is to use custom c-build method :

For example, to retrieve string in wanted format, I use this method:

static int idateformat(lua_State *L) {

    time_t t0 = (time_t) lua_tonumber(L,1); 
    const char* ptrn = lua_tostring(L,2);
    const char *tz_value = lua_tostring(L,3);

    int isinenv = 0;
    if(getenv("TZ") != NULL){
        isinenv = 1;
    }
    char old_tz[64];
    if (isinenv == 1) {
        strcpy(old_tz, getenv("TZ"));
    }
    setenv("TZ", tz_value, 1);
    tzset();
    char new_tz[64];
    strcpy(new_tz, getenv("TZ"));


    struct tm *lt = localtime(&t0);
    //"%Y-%m-%d %H:%M:%S"

    char buffer[256];
    strftime(buffer, sizeof(buffer), ptrn, lt);

    if (isinenv == 1) {
        setenv("TZ", old_tz, 1);
        tzset();
    }
    //printf("%ld = %s (TZ=%s)\n", (long)t0, buffer, new_tz);
    lua_pushstring(L, buffer);
    return 1;
} 

Only this way I would suggest.

Upvotes: 1

Related Questions