User:Pedro Oval/UnixToDateTime

From Second Life Wiki
Jump to navigation Jump to search

Convert a Unix timestamp (e.g. as obtained by llGetUnixTime) to a UTC date and time.

Adapted and optimized from this Ruby version: http://ptspts.blogspot.com/2009/11/how-to-convert-unix-timestamp-to-civil.html

Optimized for size in Mono.

Returns a list with the format [year, month, day, hours, minutes, seconds] (UTC).

This is the shortest version, but it works with positive input only (i.e. with numbers representing dates from 1970 to 2037).

list UnixToDateTime(integer unix)
{
    integer c = unix/86400;
    integer a = (c*4 + 102032)/146097 + 15;
    integer b = c + 2442113 + a + a/(integer)-4;
    c = (b*20 + (integer)-2442)/7305;
    b += c*(integer)-365 + c/(integer)-4;
    a = b*1000/30601;
    b += a*(integer)-30 + a*(integer)-601/1000;

    return (list)((integer)-4716 + c + (a>13))
           + -~((a + 10)%12)
           + b
           + unix/3600%24
           + unix/60%60
           + unix%60;
}

Size in Mono: 492 bytes.

This version also works with negative input:

list UnixToDateTime(integer unix)
{
    integer c = unix/86400;

    // LSL doesn't do floor division as required here, so we have to fix up the result
    if (unix & 0x80000000)
    {
        unix += (integer)-86400*~-c; // we're interested in unix mod 86400 from here on,
                                // but mod doesn't work well with negatives either
        if (unix^86400) --c;    // c needs fixup unless unix%86400 == 0
    }

    integer a = (c*4 + 102032)/146097 + 15;
    integer b = c + 2442113 + a + a/(integer)-4;
    c = (b*20 + (integer)-2442)/7305;
    b += c*(integer)-365 + c/(integer)-4;
    a = b*1000/30601;
    b += a*(integer)-30 + a*(integer)-601/1000;

    return (list)((integer)-4716 + c + (a>13))
           + -~((a + 10)%12)
           + b
           + unix/3600%24
           + unix/60%60
           + unix%60;
}

Size in Mono: 556 bytes.