Daylight savings and mktime in C using gcc under Linux - c

I am working with detecting Daylight saving time (summer time) transitions.
I have come across something that I don't understand, and was hoping for some explanation.
I have stripped down my code to a nearly bare minimum to show the problem.
int main(void)
{
struct tm tm1,tm2;
time_t time1, time2;
int order=0;//change this betwee 0 and 1
tm1.tm_hour=2;
if (order)
{
tm1.tm_hour=1;
}
tm1.tm_min=0;
tm1.tm_sec=0;
tm1.tm_mday=1;
tm1.tm_mon=10;
tm1.tm_year=115;
tm1.tm_isdst=-1;
time1=mktime(&tm1);
//insert here
tm2.tm_hour=1;
if (order)
{
tm2.tm_hour=2;
}
tm2.tm_min=0;
tm2.tm_sec=0;
tm2.tm_mday=1;
tm2.tm_mon=10;
tm2.tm_year=115;
tm2.tm_isdst=-1;
time2=mktime(&tm2);
printf("\n\n time stamp 1=%zu time stamp 2=%zu difference=%zi\n\n",time1 ,time2, time2-time1);
exit(0);
}
The output when order = 0 is:
time stamp 1=1446368400 time stamp 2=1446364800 difference=-3600
The output when order = 1 is:
time stamp 1=1446361200 time stamp 2=1446368400 difference=7200
(note that this is intentionally the time of the end of daylight saving time, one second after 01:59:59 on November 1st of 2015, it will be 01:00:00.)
To put it simply, the conversion of the structure when hour = 2 depends on the conversion that occurred immediately before it. One o'clock can (correctly) be either 1446364800 (standard time) or 1446361200 (DST). if the conversion before is found to DST, the second choice is used and vice versa. The obvious solution is that mktime sets some variable, that it uses the next time. However I can't find any record of it. mktime does set three (four?) external variables, tzname[0],tzname[1], timezone and daylight, but these don't seem to be causing the effect. (I did a more complicated version of my test program to test for that.)
My time zone is America/Edmonton ( MST(UTC-7)/MDT(UTC -6) )
$ gcc --version<br>
gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
Kubuntu 14.04 LTS
Any insight or pointers would be much appreciated.
Edit:
replys to comments:
1) Jonathan -- glibc version 2.19
2) chux -- printing the values of tmX.tm_isdst, tmX.tm_hour after the mktime() doesn't provide me any insight. (is that because I'm blind?) The one O'clock conversion shows an hour of one and a is_dst of either 0 or 1, exactly as infered by the timestamp. The two O'clock conversion, of course, shows an hour of 2 and an is_dst of 0.
reply to chux's(?) answer: I wonder If I have not fully explained myself.
I realize what is going on: There is an ambiguity, and it has to "guess". What I am wondering is why (and how) can it's guess depend on the previous conversion?
second edit:
to confirm Wumpus Q. Wumbley's answer inserted the following code in the place indicated in the code above:
tm0.tm_hour=0;
tm0.tm_min=0;
tm0.tm_sec=0;
tm0.tm_mday=1;
tm0.tm_mon=10;
tm0.tm_year=115;
tm0.tm_isdst=-1;
time0=mktime(&tm0);
(Basically a throw away conversion) I now get two hours difference regardless of order, so I get the DST version either way.
Thanks for the explanation.

In the current glibc source code, at time/mktime.c line 410 there is a relevant comment:
/* Invert CONVERT by probing. First assume the same offset as last
time. */
It intentionally uses the same offset in consecutive calls when possible. There is no global variable you can set to change this, or inspect to detect it. It's kept in the static time_t localtime_offset; at line 578.

The issue comes down to the value of tmX.tm_isdst before/after the mktime() call.
"A negative value causes it to attempt to determine whether Daylight Saving Time is in effect for the specified time." C11dr §7.27.2.3 2 footnote
I added printf("H:%d DST:%d\n", tm1 (or 2).tm_hour, tm1.tm_isdst); after each:
// order 0
H:2 DST:0
H:1 DST:1
time stamp 1=1446364800 time stamp 2=1446357600 difference=-7200
// order 1
H:1 DST:1
H:2 DST:0
time stamp 1=1446357600 time stamp 2=1446364800 difference=7200
The values are correct for the assumption made by the system concerning the underspecified "Y-M-D H:M:S dst=unknown" time-stamp which could go either way.
Since C does not specified what should be used during this transition hour, either assuming dst is true/false is reasonable and not necessarily consistent across various platforms. A given system, for example, could use the previous isdst setting, always 0 or flip a coin. It simply is not specified.
Note: This is an example of why some laws say "bars must close 2 hours after midnight rather than 2:00 A.M. in areas where DST transitions occurs in the 2:00/3:00 A.M. hour. 2 hours after midnight occurs only once - everyday. 2:00 A.M. occurs twice on that special transition night once a year.

Related

time function in c keeps returning -1

Hi I hava a little problem because the function time() keeps returning -1 is there any posible way to fix this?
I tried:
time_t start, end;
start = time(NULL);
//do something
end = time(NULL);
But when I debug both have the value -1.
and I tried:
time_t start, end;
time(&start);
// do something
time(&end);
But in this case both values stay 0.
It's perfectly valid, according to ISO C, for time() to return -1 if it cannot establish the time. From ISO C11 7.27.2.4 The time function /3 (though this behaviour has been around for a long time):
The time function returns the implementation’s best approximation to the current calendar time. The value (time_t)(-1) is returned if the calendar time is not available.
Given that you're working with Simplicity Studio, a package frequently used for embedded systems, it's possible your target environment may not be able to establish the calendar time (if, for example, it does not have a real-time clock to query).

How Do You Get The Last Access Time Of A File In Epoch In C?

I'm trying to get the last access time of a file in epoch format in C but I can't figure out an easy way to do so. I know you can get the last access/last modified time of a file with stat() and then using st_atime but that returns the time back in a nice human readable format. Is there any way to return the time back in epoch format?
That's puzzling; the value returned by stat() in st_atime is a time in seconds since The Epoch (1970-01-01 00:00:00 +00:00). It is not neatly formatted; you have to dissect it, probably with localtime() or gmtime() or one of the re-entrant variants of those functions, and then format it with one of the other time formatting functions (ctime(), asctime() or, better, strftime()).

getting system date(int & char mixed) using sscanf

I am trying to include system date in a program, which would calculate the total value of days since 2000. So that I could compare values of various dates (like- Antivirus update date, OS updation date) with it in order to find what is the delay in system updation. The procedure of finding date in C was killing me so I used system command to find out the current date.
system("date/t > system_date.txt");
I want to read the date from this file. There was no problem if the date was all in digits(ex.- 03/09/13). But the date displayed from DOS is of type : 03-Sep-13 . If I use sscanf as follows:
FILE *fp_date=fopen("system_date.txt","r");
char buffer[11]; int day,yr; char yr[3];
fgets(buffer,11,fp_date);
sscanf("%d-??????-%d",&day,&mon,&yr);
Now how do I scan these separately with their data types? I don't know what to use in place of ??????. Or the other method which I have been using is to store whole line in an array, then run for loops to get elements separated by '-'. But I just wanted to be a bit more sophisticated. Thanks...
You don't need system (and not even the date command). BTW, using popen("date","r") might be simpler but is still not the right way.
Read first the time(7) man page.
Then use code like
time_t now=0;
time (&now);
struct tm* ltm = localtime(&now);
The time(2) syscall gives the time from the Unix epoch (start of 1970 year) in seconds. Use clock_gettime(2) if you want more precision (or measure CPU, or thread, time). gettimeofday(2) is becoming obsolete. localtime(3) converts a Unix time to a struct tm containing seconds, minutes, ... day of week, day of month, month, .... fields. Use mktime for the opposite conversion of a struct tm to a time_t. And time_t is also given by other functions or syscalls (like stat(2) giving metadata about a file, including its modification time).
You can use fields from ltm programmatically like ltm->tm_sec for seconds, ltm->tm_min for minutes, .... ltm->tm_monfor month (0 for January, etc...), etc....
If you want a string, use strftime(3) like
char timebuf[32];
strftime (timebuf, sizeof(timbuf), "%d %b %Y", ltm);
The opposite function is strptime(3) which parses a string into a struct tm.
Notice that strftime use localization (see locale(7) first). So your user could get a french abbreviated month from %b (if his system is localized for French).
If you want universal (so called GMT) time, use gmtime instead of localtime. In multithreaded programs use localtime_r a,d gmtime_r and give them your own struct tm.
Don't do this. Obtaining the current date/time in C is trivial:
#include <time.h>
/* ... */
struct tm *tm = localtime(time(0));
The way you're trying to do it is much harder, not to mention error-prone. (For example, what happens if two instances run at the same time and both try to write to the same file?) In general, system is always the wrong way to do something.
Don't do that. Just use time(2) (C89) or gettimeofday(3) (POSIX) to get the current system time in Unix time format. If you need to convert that to other forms like a string representation or a struct tm object, then you can use various conversion functions such as ctime(3), gtime(3), and localtime(3).
#include <time.h>
time_t now = time(NULL);
printf("The current time is: %s\n", ctime(&now)); // Warning: not thread-safe
struct tm *now_tm = localtime(now); // Warning: not thread-safe
printf("Year=%d month=%d day=%d\n hour=%d minute=%d second=%d",
1900 + now_tm->tm_year,
1 + now_tm->tm_mon,
now_tm->tm_mday,
now_tm->tm_hour,
now_tm->tm_min,
now_tm->tm_sec);

What is year 2038 problem? How to find out if the existing code has that problem and solve it? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What should we do to prepare for 2038?
What is year 2038 problem?
How to find out if our code has that problem and solve it?
In C the standard 4-byte format assumes that the beginning of time is January 1, 1970, at 12:00:00 a.m. This value is 0.The maximum value of time before it rolls over to a negative (and invalid) value is 2,147,483,647, which translates into January 19, 2038. On this date, any C programs that use the standard time library will start to have problems with date calculations.To correct it simply recompile the programs with a new version of the library that uses 8-byte values for the storage format.
Try this: if the second (and third) line are not in 2038, your system has the Year 2038 problem.
#include <stdio.h>
#include <time.h>
int main(void) {
time_t x;
x = (time_t)((1U << 31) - 1);
printf("%s\n", ctime(&x));
x += 1;
printf("%s\n", ctime(&x));
x += 1;
printf("%s\n", ctime(&x));
return 0;
}
Code "running" at ideone: problematic system
Code "running" at codepad: problematic system
The programs that store or use system time in form of unsigned integers since 00:00:00 UTF will run out of range on Jan 19 2038. Although most softwares will face this problem in 2038, the ones that store future dates will get affected earlier.
The workaround will need a recompilation of (related) code that stores time in a larger storage format. Seemingly all the compiler providers are already ready with the solution.
Also, the 64 bit Operating systems are already using 64 bit wrappers for all time integers. This will put the danger well beyond our timeframe. Let the far next generations figure better solutions.

Why does localtime() set tm_isdst flag for 1 hour duration when DST ends and time falls back by one hour

I have a system configured in Moscow Time zone. Moscow goes into daylight savings time on the last sunday of March every year. Moscow Daylights Savings time (MSD) is UTC +4 hours. On the last sunday of october, daylight savings ends and it goes back to Moscow standards time (MSK) which is UTC +3 hours.
The transition from MSD to MSK happens on the last sunday of october at 3 AM. By 3 AM, the clock is reset back to 2 AM again. So on the last sunday of october, there will be two instances of 2 AM. At the first instance of 2 AM, Moscow is still in MSD (UTC +4). At the second instance of 2 AM Moscow is in MSK (UTC +3).
My query is, if I use localtime() function to get the local timezone information at the second instance of 2 AM on the last sunday of october, will the tm_isdst flag be set by localtime() or will it not be set. My observation is that the tm_isdst flag is set by localtime() during the one hour window 2 AM - 3 AM (the second instance) in MSK. Is this bug or is it an expected behavior?
For the records, my timezone/Europe tz database file is upto date and the corresponding timezone database file is properly compiled by zic compiler as /usr/share/zoneinfo/Europe/Moscow.
From a little research in the specs, it looks like C determines all of this info from environment variables. In this case, the TZ environment variable is specified for POSIX. Windows stores it in a registry location.
During this 1 hour period, you are clearly no longer in daylight savings time, so by the definition of the tm_isdst flag, it should be clear.
To know if it is a bug with the compiler/library implementation or OS, you would have to examine the environment variable value directly during this period.

Resources