In my case I need to get the current date and the date 14 days later as a time limit for returning a book. Is there any such function or a manipulation to an existing function?
Given a broken-down time structure, struct tm, the Standard C (and POSIX) function mktime() will return a time_t value associated with the value. Further, the elements of the structure passed in can be out of their normal ranges, and mktime() will normalize them. So, you could add 14 to the tm_mday element of the structure, and mktime() will both give you the time_t value for the corresponding time and also normalize the elements of the structure, thus giving you the correct day of the month, month of the year, and year number.
Related
So mktime() returns a time_t value which is defined as "an integral value representing the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC" (source). I can convert a date to a time_t value by using mktime(). For example, to convert the date 10-Sep-2017 08:34:56 to a time_t I'd do the following:
struct tm tm;
time_t tv;
tm.tm_sec = 56;
tm.tm_min = 34;
tm.tm_hour = 8;
tm.tm_mday = 10;
tm.tm_mon = 8;
tm.tm_year = 117;
tm.tm_isdst = ????;
tv = mktime(&tm);
Now what I don't understand is the idea behind the tm_isdst parameter: It is described as "a flag that indicates whether daylight saving time is in effect at the time described" (source).
This description is somewhat confusing me because I'm of the opinion that the time I'm describing in struct tm is in fact already a UTC time and the time_t value I want to have from mktime() is UTC as well. But UTC time doesn't change with a change of seasons, so why does mktime() need to bother with daylight saving time at all? Isn't the advantage of using UTC instead of local time that I won't have to bother with daylight saving time? So why do I have to set tm_isdst then?
I'm sure the answer is really simple but at the moment I'm failing to see it. Could somebody please provide a simple example that illustrates why mktime() needs the tm_isdst parameter to convert a certain date and time to a time_t value?
Whether DST is in effect changes what the epoch time will be because mktime uses the current time zone to determine the time.
For example, if I populate tm with 1/1/70 00:00:00 as follows:
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
tm.tm_mday = 1;
tm.tm_mon = 0;
tm.tm_year = 70;
tm.tm_isdst = 0;
I get a value of 18000 for tv because my timezone is GMT-5 (18000 = 3600 * 5). If I change the value of tm_isdst to 1, then tv will be set to 14400 (3600 * 4).
Setting tm_isdst to -1 will look at the local timezone database to see if DST is in effect for the given date/time.
Now what I don't understand is the idea behind the tm_isdst parameter:
It is described as "a flag that indicates whether daylight saving time
is in effect at the time described" (source).
This description is somewhat confusing me because I'm of the opinion
that the time I'm describing in struct tm is in fact already a UTC
time
Well, that's your main problem. Per its documentation, which you already linked, mktime() converts a time structure expressed as local time to a time_t.
and the time_t value I want to have from mktime() is UTC as well.
Again according to the docs, when a time_t is interpreted as an absolute time, it represents the number of seconds elapsed since the Epoch, in UTC, so that's indeed what you will get from mktime(). But that means that there is, in general, a time zone and possibly daylight-saving difference between the two representations.
The C library relies on contextual localization data for the time zone applicable to local time, but although it knows the current rules for daylight saving time, it does not necessarily know the rules that were in effect at the specified time. Moreover, there are edge cases at the changeovers between daylight time and standard time. For these and perhaps other reasons, you need to tell mktime() whether the time given refers to daylight saving time or standard time.
But UTC time doesn't change with a change of seasons, so why does
mktime() need to bother with daylight saving time at all?
Because mktime() accepts local time as input.
Isn't the
advantage of using UTC instead of local time that I won't have to
bother with daylight saving time?
That is one of the advantages, yes.
So why do I have to set tm_isdst
then?
Because mktime() accepts local time as input.
struct tm can be thought of as a timestamp.
Example: When a timezone goes from daylight time to standard time, the "day" has 25 hours and struct tm needs more info than just "Y-M-D h:m:s".
The local time may be 2:30 AM daylight time and then 1 hour later it is 2:30 AM standard time. .tm_isdst is especially useful to distinguish that case. Note that .tm_isdst is relevant in all timestamps.
As struct tm itself does not contain the timezone (that info exist elsewhere), .tm_isdst is designed to provide time stamps indication of standard time or daylight time (or even unknown standard/daylight).
If the .tm_isdst is set to -1 (unknown) and the timezone is UTC, then the expectation is that, for all timestamps, it is as if .tm_isdst == 0.
I'm trying to calculate the day of week from a seconds since epoch timestamp. From time.h I can use gmtime(), but this increases the program with 1.3kB, probably because gmtime() also calculates the date.
So, I'm wondering what would be wrong about using something like:
(timestamp / (24*3600)) % 7
The only thing I could think of is leap seconds, such that something like 00:00:02 could be classified as the wrong day.
edit
This is for embedded programming, 1.3kB is a substantial part of the 64kB program/firmware. Furthermore, I'm not expecting to do anything with timezones or dates after this.
what would be wrong about using something like: (?)
(timestamp / (24*3600)) % 7
Not much wrong with the above except you have not specified the day of the week the epoch began (e.g. Thursday) nor the day of the week the week begins on (e.g. Monday). See 8601 for a deeper discusison on the first day of the week. Also watch out for computations like 24*3600 that with 16-bit int/unsigned lead to troubles.
Example: Let us say the epoch began on day-of-the-week number 3 (Monday:0. Thursday:3). This takes care of 2 issues at once: day of the week of the epoch and the first day of the week as only the positive difference needs to be coded.
#define EPOCH_DOW 3
#define SECS_PER_DAY 86400
dow = ((timestamp / SECS_PER_DAY) + EPOCH_DOW) % 7;
If timestamp is a signed type, append the following to insure a result in the [0...6] range.
dow = (dow + 7) % 7;
// or
if (dow < 0) dow += 7;
I doubt leap seconds are used in your application. If they are, the task is far more complicated as code then needs to deal with not only with a more complex calculation, but how to receive updates of the next scheduled leap-seconds - they occur irregularly.
You're off by 4, since January 1, 1970 was a Thursday, and you may compute an incorrect result for dates before the epoch depending on the behavior of % on negative operands. (The simplest fix is to check whether the result is negative, and if so add 7.) But other than this, your algorithm is correct; it's the same as used by glibc internal function __offtime, which gmtime ultimately ends up calling. (You can't call it yourself, as it's an internal implementation detail).
There's no need to worry about leap seconds; Unix time ignores them.
I would recommend encapsulating the code in a (possibly inline) function, with the gmtime implementation as a comment of #if 0 block, so that you can easily switch to it if you start needing to compute months/years as well.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C Program to find day of week given date
I have a calendar file that gives dates as "20121027T190000" and I need to convert that to "Wednesday, October 27 2012, 1900". Is there a C function that computes the day of the week?
Yes, the standard localtime() function converts from a time_t to a struct tm that includes the day of the week. To create a time_t value, you can use the mktime() function to convert from a struct tm to a time_t (you do not have to fill in the day of the week when using mktime()).
This might seem like a roundabout way to do this, but it's reasonably straightforward and uses standard library functions.
My code receives a time_t from an external source. However, that time_t isn't acutally based on UTC Epoch time, along with it I get a timezone string (eg, EDT, PST, etc), and its based on this offset'ed epoch. I need to convert this to a true UTC Epoch based time_t.
Additionally, I need to be able to go in the opposite direction, taking a UTC Epoch based time_t and a timezone, and create the offsetted time_t, but in this situation instead of having a timezone like EDT/PST), etc, I have a Unix style timezone description like "America/New York" and need to convert to the correct timezone given daylight savings, so I'd need to get back from the algorithm, both an offsetted time_t, and the correct descriptor (EDT,EST).
I'm pretty sure I can pull this off by temporarily changing tzset() and some combination of conversions between broken-down time, time_t and timeval, but doing this always makes my brain hurt and makes me feel like I'm missing something obvious. Can anyone recommend some code or sudo-code to do this or at least a proper approach?
time_t is in seconds, so just offset your time_t values by 3600 times the number of hours the timezone is offset by. As long as you have the offset specifically identified (i.e. EST or EDT instead of US/Eastern or EST5EDT or whatnot) then this is really simple and not prone to errors.
would any of these functions help you? localtime(), gmtime(), etc.
The function mktime takes a struct tm as argument. One of the members of struct tm is tm_isdst. You can set this to 1 for wintertime, 0 for summertime, or -1 if you don't know.
However, if during winter, you try to convert 2009-09-01 00:00, mktime fails to see that although it is currently winter, the date you are converting is summertime. So the result is one hour off. For me (GMT+1) it's 2009-08-31 22:00, while it should be 23:00.
Is there a way to determine if a particular date is in the summer or wintertime period? Is it possible to convert a summer date to utc in the winter?
(I hit upon this problem trying to answer this question)
This is one of the (many) deficiencies in the time handling interfaces in Standard C. See also the Olson time zone database. There isn't an easy way to find when a time zone switches between winter and summer (daylight saving and standard) time, for example. Anything in the future is, of course, a prediction — the rule sets change often (the current release is 2017a).
Is there as far as you know, a UNIX specific solution?
I took a look at the code in tzcode2017a.tar.gz, and the mktime() there behaves as you want if you set the tm_isdst to -1 (unknown). So, if you use that (public domain) code, you would be OK - probably. Quoting from 'localtime(3)' as distributed with the Olson code:
Mktime converts the broken‐down time, expressed as local time, in the structure pointed to by tm into a calendar time value with the same encoding as that of the values returned by the time function. The original values of the tm_wday and tm_yday components of the structure are ignored, and the original values of the other components are not restricted to their normal ranges. (A positive or zero value for tm_isdst causes mktime to presume initially that summer time (for example, Daylight Saving Time in the U.S.A.) respectively, is or is not in effect for the specified time. A negative value for tm_isdst causes the mktime function to attempt to divine whether summer time is in effect for the specified time; in this case it does not use a consistent rule and may give a different answer when later presented with the same argument.)
I believe that the last caveat about a 'consistent rule' means that if the specification of the time zone changes (for example, as when the USA changed from 1st week in April to 2nd week in March for the change to Daylight Saving Time) mean that if you determined some time before the rule changed and after the rule changed, the same input data would give different outputs.
(Note there are useful HTML files in ftp://ftp.iana.org/tz/ directory, such as ftp://ftp.iana.org/tz/tz-link.html.)