TZ, localtime and strftime problem on AIX and Solaris

Hello all,
I have the following code that seems to be misbehaving depending on the timezone setting (TZ Environment variable). It gives the correct value when TZ is in POSIX format and the wrong value when in OLSON format.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <memory.h>
int main()
{
    long secs;
    char timeString[20];
    struct tm timeHolder;
    for(secs=0; secs < 3610; secs++)
    {
        localtime_r((const time_t *) &secs, (struct tm *) &timeHolder);
        memset( timeString, 0, sizeof( timeString));
        strftime( timeString, sizeof( timeString), "%H:%M:%S\0", &timeHolder);
        printf("Secs: %d\t\t\tTime: %s\n", secs, timeString);
    }
}
 

I compile and link this as follows:

gcc -o timeprob.exe timeprob.c

The run below is on AIX 6.1 (oslevel -r gives 6100-05). Same happens on Solaris 10.

date
Fri Apr 26 16:44:25 BST 2013

date -u
Fri Apr 26 15:44:38 GMT 2013

So currently we are 1 hour ahead of GMT with Daylight Savings in operation.

1] First with POSIX format TZ:

echo $TZ
GMT0BST,M3.5.0,M10.5.0

./timeprob.exe
<snip>
Secs: 3599 Time: 00:59:59
Secs: 3600 Time: 01:00:00
Secs: 3601 Time: 01:00:01
<snip>

ie. at 3600 secs from epoch the time shows correctly as 1 hour from epoch.

2] Next with OLSON format TZ:

echo $TZ
Europe/London

./timeprob.exe
<snip>
Secs: 3599 Time: 01:59:59
Secs: 3600 Time: 02:00:00
Secs: 3601 Time: 02:00:01
<snip>

ie. at 3600 secs from epoch the time shows wrongly as 2 hours from epoch.

  • 'date' from Unix prompt shows the date correctly with/without DST.
  • When there is no DST both format work correctly.

Any idea what the problem could be? I would expect both POSIX and OLSON formats should give the same output ie. either both should say 1 hour from epoch or both should say 2 hours from epoch.
The libc.a function used is that which comes with AIX 6.1.

Any help appreciated.

Regards

Can you post the output of the following command...

ls -la /usr/share/lib/zoneinfo/Europe

I ran your code. The reason is because in 1970 daylight savings did not work the way it does now. I edited you code and added a %c to the format string + more space in the output string:
This is what I get with Mountain/Denver TZ on Solaris:

Secs: 3599 Time: Wed Dec 31 17:59:59 1969 17:59:59
Secs: 3600 Time: Wed Dec 31 18:00:00 1969 18:00:00
Secs: 3601 Time: Wed Dec 31 18:00:01 1969 18:00:01

FYI: DST does not work in winter in London, and most countries including North America had odd ball timezone settings way back then, if they even had it. I could go on. Your long variables "secs" should also be a time_t. Try starting with:

secs=1367265312

and count forward from there.

Thanks for replying.
You may have found the problem (partially)...

On our AIX machine, the 'Europe' folder does not exist.
However we have a file called GB-Eire under the /usr/share/lib/zoneinfo directory.

When I set TZ to GB-Eire, I get the correct output (ie. same output as when I set TZ to Posix format GMT0BST,M3.5.0,M10.5.0)

I changed the strftime and the timeString variables as follows:

 char timeString[30];
strftime( timeString, sizeof( timeString), "%d-%b-%Y %H:%M:%S", &timeHolder);

<snip>
Secs: 3599 Time: 01-Jan-1970 00:59:59
Secs: 3600 Time: 01-Jan-1970 01:00:00
Secs: 3601 Time: 01-Jan-1970 01:00:01
<snip>

But on our Solaris machine, we have the 'Europe/London' folder and file, a GB file and a GB-Eire file. Setting TZ to any of these does not work. All give:

<snip>
Secs: 3599 Time: 01-Jan-1970 01:59:59
Secs: 3600 Time: 01-Jan-1970 02:00:00
Secs: 3601 Time: 01-Jan-1970 02:00:01
<snip>

Which is different from what I get when I set TZ to Posix format : GMT0BST,M3.5.0,M10.5.0

<snip>
Secs: 3599 Time: 01-Jan-1970 00:59:59
Secs: 3600 Time: 01-Jan-1970 01:00:00
Secs: 3601 Time: 01-Jan-1970 01:00:01
<snip>

Strange...so it looks like it might work correctly when I get the 'Europe/London' file under zoneinfo folder on AIX (will need to test this)...but not sure why it does not work on Solaris.

---------- Post updated at 01:45 PM ---------- Previous update was at 01:09 PM ----------

Thanks for replying.
I agree that the DST does not apply in winter in London. But I would expect that if I set TZ in Posix (GMT0BST,M3.5.0,M10.5.0) or Olson (Europe/London) formats, I should get the same output (this is on Solaris where I have the '/usr/share/lib/zoneinfo/Europe/London' file).

When I try starting at 1367275312 onwards it does match. But then these are when DST is ON and it always works correctly (as in both posix/olson outputs match) when DST is ON. Same when I set to 8598706 (when DST is ON and in the 1970s):

Secs: 8598706 Time: 10-Apr-1970 13:31:46

On both formats, I get the same answer.

So the problem exists only when DST is off and looking at my reply to 'Shamrock' above, maybe only on Solaris (as AIX seems to work for GB, EB-Eire and if I have 'Europe/London' may work too).

Summer Time Act 1972

IANA ? Time Zone Database

Have a look. DST onset changes over time. If you want to test timezones, use now, not way back when. Or look at the source for those timezone files you are using. The IANA link. It is in human readable text.

1 Like

Not sure why it doesnt work on Solaris...I can only talk about AIX as that is the machine I use. However you can try to get the latest timezone patch for your Solaris machine. Btw what is the os version for your Solaris box and compare the outputs of the following commands on AIX and Solaris and see if there is any difference which might hint at a timezone patch...

zdump -vc 1970 GB
zdump -vc 1970 GB-Eire
zdump -vc 1970 Europe/London

Obviously you cant run the last command on AIX as it doesnt have the Europe/London timezone info file but post the outputs of those commands here so all can look and suggest a solution...

1 Like

Thank you both.
That seems to be the problem - mystery solved - and both were correct !

Under OLSON format the TZ depends on the data in /usr/share/lib/zoneinfo and under POSIX format we specify the DST details directly and so it does not depend on anything else.

Using zdump -vc to dump the zoneinfo database shows that there are gaps in the data stored w.r.t. DST for different years.
Specifically in the cases where the above code does not work the data for 1970 is missing.

We have another AIX machine where Europe/London was available but details for 1970 is missing and so the code gives the wrong output:

zdump -vc 1970 Europe/London
<snip>
Europe/London Sun Oct 29 02:00:00 1967 UTC = Sun Oct 29 02:00:00 1967 GMT isdst=0
Europe/London Sun Feb 18 01:59:59 1968 UTC = Sun Feb 18 01:59:59 1968 GMT isdst=0
Europe/London Sun Feb 18 02:00:00 1968 UTC = Sun Feb 18 03:00:00 1968 BST isdst=1
Europe/London Sat Oct 26 22:59:59 1968 UTC = Sat Oct 26 23:59:59 1968 BST isdst=1
Europe/London Sat Oct 26 23:00:00 1968 UTC = Sun Oct 27 00:00:00 1968 BST isdst=0
Europe/London Mon Jan 18 03:14:07 2038 UTC = Mon Jan 18 03:14:07 2038 GMT isdst=0
Europe/London Tue Jan 19 03:14:07 2038 UTC = Tue Jan 19 03:14:07 2038 GMT isdst=0
<snip>

And where the data is available (and correct), the code gives the right output.

So the moral of the story is :
1) Using Posix format is reliable and to be preferred
2) If using Olson format check the zoneinfo database using zdump and if the data for the year is there and correct all is well. Otherwise first ensure that the zoneinfo database is corrected.