DST restoration under Linux in C - c

I have date/time information from Berlin,Germany.
For example:
2011-05-16 12:24:23,
2011-01-21 17:00:31
Unfortunatly, these times have NO daylight saving information. I know that the first date is CEST and the second time is CET.
I could write a check whether the date/time is daylight saving or not.
The summertime starts at the last sunday in march at 2:00 AM, and ends at the last sunday in october at 3 AM.
Self developing such a check seems error prone to me. Is there something that can be already used under Linux in C?
Thank you for your help.

You can convert the time to a time_t with mktime() and then pass it back in to localtime() which will set tm_isdst. Both mktime() and localtime() utilize your local system's time configuration, so you're really discovering if the timestamp is in DST where you are. The obvious problem here is that you have a timestamp string without geographical information so the best you can do is assume it's for your current location.

You can pass the %Z format argument to the date command to obtain the timezone from a date, then determine if DST was in effect from the timezone's name:
$ date -d '2011-05-16' '+%Z'
CEST
$ date -d '2011-01-21' '+%Z'
CET

Related

Confused about UTC

I am not very clear about the time() function.
"man 2 time" says "time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC)."
My question is
Suppose device A is in London, device B is in USA.
Does the time() return same value or not? Or does the time() result change with timezone?
====update====
I know my real problem. I thought UTC is a timezone. Since Wikipedia says "In some countries where English is spoken, the term Greenwich Mean Time (GMT) is often used as a synonym for UTC" then I was thinking, the time() in USA should return (A+B). A is current USA to "1970-01-01 00:00:00 +0000" in USA. B is time difference of (1970-01-01 00:00:00 +0000 USA to1970-01-01 00:00:00 +0000 GMT ). Seems I am totally wrong.
The number of seconds since the start of 1970 UTC doesn't vary based on where you are located in the world, so time returns the same regardless of where you are located in the world (assuming correct system clocks).
Conversions to local time is performed by subsequent operations.
$ TZ=America/Toronto perl -MPOSIX -le'
my $time = time();
print $time;
print strftime("%FT%TZ", gmtime($time));
print strftime("%FT%T%z", localtime($time)) =~ s/(?=..\z)/:/sr;
'
1552516168
2019-03-13T22:29:28Z
2019-03-13T18:29:28-04:00
$ TZ=America/Halifax perl -MPOSIX -le'
my $time = time();
print $time;
print strftime("%FT%TZ", gmtime($time));
print strftime("%FT%T%z", localtime($time)) =~ s/(?=..\z)/:/sr;
'
1552516168
2019-03-13T22:29:28Z
2019-03-13T19:29:28-03:00
[Oops, I thought this question was tagged perl. However, the code should be clear enough to convey the idea to a C programmer. time, gmtime, localtime and strftime behave similarly in both languages.]
Assuming your system time is set properly, the timezone in which the machine resides makes no difference as to what time() returns, since–as you have already acknowledged–UTC is by definition universal and does not vary from location to location.

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

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?
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.

Where does the timezone for date and strftime come from?

Im curious because I checked on a linux host in Sydney, Australia and the date command says EST as the timezone, as does strftime(tz, sizeof(tz), "%Z", &time) when running a simple C binary to print that out. However, I know the timezone is AEST. Are timezone abbreviations truncated? Where can I find out more about this?
Australian time zone abbreviations changed in tzdb 2014f, released in August 2014.
You simply need to update your time zone data file to the current version (2015b as of this writing). On linux, this is usually in the tzdata package, which you can update using apt-get, or rpm, or whatever is appropriate for your distro.
the current timezone is typically in an environment variable and/or in a special file in /etc/ in linux

How to set the timezone permanently in ubuntu using C program

When i write -
root#XYZ:/home/timez# export TZ=UTC; date
Thu Nov 13 05:35:36 UTC 2014
It change the date & timezone. I want a equivalent C program of this.
I wrote a C program to set Timezone in my Ubuntu machine using code -
system(" export TZ=CST6CDT; date ");
i can see the date in CST as output but this program is not setting Ubuntu Timezone to CST, it is still in UTC.
There exists a settimeofday call inherited from Unix V7 or even before ... that used to set a time zone value in the kernel. But my current man says now : Note: timezone is no longer used; this information is kept outside the kernel.
So in system less than 20 years old, the time zone is only kept in the environment. And the environment has the following property :
a child inherit the environment of its parent but cannot modify its parent's environment
That means that any C program can modify its TZ via a simple setenv call, and this new timezone will be used by itself and all its childs, but it will never be able to modify the environment of the shell that started it. The only possibility would be a special API offered by shell programs, but I know none that implements such a thing.
I know it is a you can't answer but it is the best I can do ...

how to convert time_t to something like "Fri, 12 Nov 2010 16:02:54 GMT " in C on Linux

I'm writing a simple web server in C on Linux.
I have to add the last modified time of a file that will be transferred to the client(browser),
I analysed how some websites and find out that they all present the time in format:
Fri, 12 Nov 2010 16:02:54 GMT,
my question is, can I transfer a time_t value to something string in the former format simply? Is there a function to do this? Or is the format unimportant at all?
strftime() is the function you need.
The wikipedia article on time_t gives a good example
http://en.wikipedia.org/wiki/Time_t
That looks like the format defined in RFC 822, you can convert a time_t to a struct tm, and format it to a using strftime string like
struct tm time_tm;
char http_time[64];
time_t t = time(NULL);
gmtime_r(&t,&time_tm);
strftime(http_time,sizeof http_time,"%a, %d %b %Y %H:%M:%S +0000",&time_tm);
NOTE; strftime converts the names using the current locale, you might need to change the current locale to get the English names.
The HTTP spec also allow the format given by asctime()

Resources