Tuesday, March 15, 2022

[SOLVED] C program delivers only the UTC time as localtime on Linux using GCC

Issue

I have a C program that runs on two different RHEL6 servers that are configured with the same timezone. The C program uses the time functions from time.h. On one of the servers the local time is correctly determined, on the other one the UTC (default) time is displayed independent from the configured timezone.

I've tried to see if the link to /etc/localtime is broken but it's a correct softlink to /usr/share/zoneinfo/<timezone> (in this case Europe/Berlin). I've inspected the timezone file with zdump and the content of the file is correct. The timezone and time of the system is also correctly displayed using date. There is no definition of the $TZ variable in my bash or anywhere else!

As an additional test I have run the follwing code with and without a $TZ variable:

    ::time_t aclock;
    ::tm tm_tmp;
    ::tm *newtime;

    setenv("TZ", "Europe/Berlin", 1);
    tzset();
    ::time( &aclock );
    newtime = ::localtime_r( &aclock, &tm_tmp );
    printf("\nDEBUG TIME: %d ", aclock);
    printf("\nDEBUG TIMEZONE: %s \n", newtime->tm_zone);
    printf("DEBUG HOUR: %d \n", newtime->tm_hour);

Using the code above and setting TZ parameter differently I get the following outputs on the faulty server, assuming that the server time is Europe/Berlin, CEST at this moment:

without setenv:
DEBUG TIME: 1524241319
DEBUG TIMEZONE: UTC
DEBUG HOUR: 16

setenv("TZ", "Europe/Berlin", 1);
DEBUG TIME: 1524241319
DEBUG TIMEZONE: Europe
DEBUG HOUR: 16

setenv("TZ", "/etc/localtime", 1);
DEBUG TIME: 1524241319
DEBUG TIMEZONE: CEST
DEBUG HOUR: 18

So it looks like the "Europe/Berlin" time cannot be found, as the UTC time is displayed and the timezone "Europe" is invalid.

As I said the output / behavior on the other machine is the expected one:

without setenv:
DEBUG TIME: 1524241711
DEBUG TIMEZONE: CEST
DEBUG HOUR: 18

setenv("TZ", "Europe/Berlin", 1);
DEBUG TIME: 1524241711
DEBUG TIMEZONE: CEST
DEBUG HOUR: 18

setenv("TZ", "/etc/localtime", 1);
DEBUG TIME: 1524241711
DEBUG TIMEZONE: CEST
DEBUG HOUR: 18

P.S. the same gcc version 4.4.7 is used on both machines.

Is it possible that my timezone database is corrupt on the faulty server? Has someone faced similar problem and solve it?


Solution

I finally figured out, that the problem was the libc.so library, which was differently compiled for one of the machines and only used for some C applications excepting linux himself. This explains why date delivers the wright output but the C program not. Using ldd libc.so I've found out that the linker was also set to be at the path /home/mqm/lib as default, which dosn't fit to my server /home/mqm/lib/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2. To resume, here is the full solution:

Problem: Your Linux system is delivering the wright date and time using date or some applications but wrong output using C programs.

Solution: After ensuring that there is no programming error in your code, check with

strace -e trace=open,close,read,write,connect,accept yourCProgram

which path is used to get the time/timezone. You can also check ldd libc.so to see where the default path of the linker is. If the paths are not corresponding to your linux system configuration, consider recompiling the C library to fit to your system configuration or set $TZ='fullpathtotimezone' as a hotfix / workaround.



Answered By - AsamRegnat
Answer Checked By - David Marino (WPSolving Volunteer)