Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Discussion: UTC Date-time vs. UNIX time_t

AnneDroid Lily
Scary robot girl. Rarr.
Join date: 10 Nov 2003
Posts: 41
08-02-2005 01:14
The time associated with the email event is given in the UNIX time_t format (as a string). It is the only function or event that uses this format.

Recently, I have become interested in comparing the email time with the UTC Date-time (YYYY-MM-DDTHH:MM:SS.FFZ) from llGetTimestamp.

Here is what I've come up with for conersions between the two:

From UTC to time_t
CODE
list julian = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];

integer UTC2time_t(string UTC)
{
time = llParseString2List(UTC, ["-","T",":","Z"], []);
integer year = llList2Integer(time, 0);
integer month = llList2Integer(time, 1);
integer day = llList2Integer(time, 2);
integer hour = llList2Integer(time, 3);
integer min = llList2Integer(time, 4);
integer sec = llFloor(llList2Float(time, 5) + 0.5);
integer leapDays = 7 + llFloor((year - 2004) / 4);
// my count says that there has been 9 leap days since 1970, but 7 makes the function match an actual timestamp.
seconds = (year - 1970) * 31536000 + (llList2Integer(julian, month - 1) + day + leapDays) * 86400 + hour * 3600 + min * 60 + sec;
return seconds;
}


From time_t to UTC (there is likely a better way to write this)
CODE
string month;
integer date;
string time_t2UTC(integer seconds)
{
string UTC = "";
integer years = llFloor( seconds / 31536000);
integer leapDays = 7 + llFloor((years - 34) / 4);
// my count says that there has been 9 leap days since 1970, but 7 makes the function match an actual timestamp.
seconds = seconds - years * 31536000 - leapDays * 86400;
// seconds will be negative on Jan 1 of a leap year
UTC = (string)(1970 + years);
integer days = llFloor(seconds / 86400);
if (days > 335)
{
month = "-12-";
date = days - 335;
}
else if (days > 305)
{
month = "-11-";
date = days - 305;
}
else if (days > 274)
{
month = "-10-";
date = days - 274;
}
else if (days > 244)
{
month = "-09-";
date = days - 244;
}
else if (days > 213)
{
month = "-08-";
date = days - 213;
}
else if (days > 182)
{
month = "-07-";
date = days - 182;
}
else if (days > 152)
{
month = "-06-";
date = days - 152;
}
else if (days > 121)
{
month = "-05-";
date = days - 121;
}
else if (days > 91)
{
month = "-04-";
date = days - 91;
}
else if (days > 60)
{
month = "-03-";
date = days - 60;
}
else if (days > 31)
{
month = "-02-";
date = days - 31;
}
else
{
month = "-01-";
date = days;
}
if (llFloor((years - 34)/4) == (years - 34) / 4)
{
// if leap year and before feb 29, add the leap day back in.
if (days < 59)
{
date = date + 1;
seconds = seconds + 86400;
if (days == 31)
{
month = "-02-";
date = 1;
}
}
else if (days == 59)
{
month = "-02-";
date = 29;
seconds = seconds + 86400;
}
}
UTC = UTC + month + llGetSubString("0" + (string)date, -2, -1) + "T";
seconds = seconds - days * 86400;
integer hours = llFloor(seconds / 3600);
integer minutes = llFloor((seconds - hours * 3600) / 60);
seconds = seconds - hours * 3600 - minutes * 60;
UTC = UTC + llGetSubString("0" + (string)hours, -2, -1) + ":" + llGetSubString("0" + (string)minutes, -2, -1) + ":" + llGetSubString("0" + (string)seconds, -2, -1) + ".0Z";
return UTC;
}


I hope you find these functions at least moderately useful.
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
08-03-2005 09:43
/15/9b/56183/1.html
_____________________
i've got nothing. ;)
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
08-03-2005 11:58
If you are in January or February of a leap year, you need to subtract one from leapDays (year%4==0 is easier than the full formula, and works from 1901 to 2099).

Your nine leap days is correct, but getting skewed by the constant array (its February has 29 days instead of 28), and the day number (0th day of the month is 1).

I would write it "leapDays = (year - 1968) / 4;", just to avoid the magic nine (2000 was a leap year because it is divisible by 400).
Francis Chung
This sentence no verb.
Join date: 22 Sep 2003
Posts: 918
08-03-2005 12:51
You know what they say about great minds ;)
/15/c7/36315/1.html
_____________________
--
~If you lived here, you would be home by now~
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
08-03-2005 19:28
I'm going to stick with the previous implementation...


you don't need to use floor here...

integer leapDays = 7 + llFloor((year - 2004) / 4);

your numbers are already integers.
More importantly it's possible for very large years that you will loose data.

integer leapDays = 7 + (year - 2004) / 4;

which can be simlified to...

integer leapDays = (year - 1976) / 4;

integer leapDays = (year / 4) - 494;

_____________________________

integer sec = llFloor(llList2Float(time, 5) + 0.5);
this can be simplifed to

integer sec = (integer)(llList2Float(time, 5) + 0.5);

but should you really be rounding seconds in a date?

integer sec = llList2Integer(time, 5);
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
AnneDroid Lily
Scary robot girl. Rarr.
Join date: 10 Nov 2003
Posts: 41
08-05-2005 03:23
Minsk: I like your "year%4==0" idea. For some reason, the use of moduli doesn't often enter my head.

Francis: Doh. That's what I get for not being a forum regular.

Strife: If I'm still around when the year number is high enough to cause data loss, I'll be sure to check this script ;)
Is casting really faster than llFloat, or is that suggestion stylistic?
As it turns out, my reasoning for using rounding on the seconds was flawed. They should be truncated as you described.

(edited for spelling)
Minsk Oud
Registered User
Join date: 12 Jul 2005
Posts: 85
08-05-2005 04:01
llFloor versus typecasting should be pretty much identical in LSL. I suspect most programmers would write it (and expect it) as a typecast, because the floor function in most languages returns a floating-point value (whereas in LSL it is an integer).

The 1976 and 494 constants that Strife suggested are adjusted to account for two days worth of bugs. IMO it would be a lot safer to fix the bugs and use the "right" values (it also means the code will actually work for dates back to 1970, rather than inexplicably being off).

<edit>Given that integer-seconds-from-1970 can only _represent_ 1902 through 2038, and very few implementations support earlier than 1970... mod 4 is correct. When we move to a 64-bit representation it would be worth including the full (x%4==0) && (x%100 != 0 || x%400 == 0) rule, for the moment it is just being pedantic.</edit>
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
08-05-2005 04:53
Although you might not be here for it the year%4==0 doesn't actually work - it generates 3 false leaps years every 400 years (terrible isn't it).

IF year%100==0 && year%400==0 then it's a leap year (like 2000 was), but 1900 wasn't and 2100, 2200 and 2300 won't be.