Timezone offset


#1

I’m having a problem with timestamps.

My app -which I want to port to Juce - employs this convention for timestamps:

They are written like {yyyy-mm-dd hh.ii.ss.nnnZ} where Z is a letter that encodes the timezone (like GMT+2 etc.)

I’m quite satisfied with this scheme - it means my human eye reads local time but the parser gets the GMT right, regardless of the setting of the machine, so the stamps don’t get messed up when sent across timezones.

So I want to create the Time as GMT from the year-month-… fields, and then apply a correction deduced from the timezone mark.

May I suggest a small feature that would help me in implementing this, and might be useful to others as well:

Could the Time(const int year,…) constructor be augmented with an additional optional parameter:

[b]bool useLocalTime=true[/b]

so that supplying false will construct the time as GMT regardless of local time?

Here is a shot at how it might be implemented - using the “extended maths” for GMT conversion.

[code]Time::Time (const int year,
const int month,
const int day,
const int hours,
const int minutes,
const int seconds,
const int milliseconds,
const bool useLocalTime) throw()
{
jassert (year > 100); // year must be a 4-digit version

if (year < 1971 || year >= 2038 || !useLocalTime)
{
    // use extended maths for dates beyond 1970 to 2037..
    const int timeZoneAdjustment;
    if (useLocalTime)
        timeZoneAdjustment = 31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000);
    else timeZoneAdjustment = 0;
    const int a = (13 - month) / 12;
    const int y = year + 4800 - a;
    const int jd = day + (153 * (month + 12 * a - 2) + 2) / 5
                       + (y * 365) + (y /  4) - (y / 100) + (y / 400)
                       - 32045;

    const int64 s = ((int64) jd) * literal64bit (86400) - literal64bit (210866803200);

    millisSinceEpoch = 1000 * (s + (hours * 3600 + minutes * 60 + seconds - timeZoneAdjustment))
                         + milliseconds;
}
else
{
    struct tm t;
    t.tm_year   = year - 1900;
    t.tm_mon    = month;
    t.tm_mday   = day;
    t.tm_hour   = hours;
    t.tm_min    = minutes;
    t.tm_sec    = seconds;
    t.tm_isdst  = -1;

    millisSinceEpoch = 1000 * (int64) mktime (&t);

    if (millisSinceEpoch < 0)
        millisSinceEpoch = 0;
    else
        millisSinceEpoch += milliseconds;
}

[/code]

(If you don’t like it, I’ll just copy the math to my own code. But I think it might be useful for others to allow explicit timezone corrections rather than being tied to the timezone of the system.)


#2

Ok, that makes a lot of sense, I’ve no objection to adding it, thanks!


#3

Thanks - but beware I didn’t test it thorought. I did try to be careful not to change the behaviour of the default useLocalTime=true case, so it shouldn’t break other people’s code.

I’m no C library expert but it might seem more consistent to use the _mkgmtime function, and then again I have no idea if this works for other compilers than VC9, so maybe it’s better to leave it as I wrote it.


#4

Well, I can’t see any problems with that code. If it works at all, I think it’s probably fine. Shouldn’t affect any old code, either.