How to convert from a struct tm to a time_t ?

R

Richard Bos

Angus Comber said:
I need to do this conversion but can't seem to find the function.

What conversion?

*Looks up*

Oh. Please don't do that: put your complete question into the body of
the post, as well.

For others who might be reading this: the conversion in question is from
a struct tm to a time_t.

The function you want is mktime().

It is also useful for normalising struct tm's, when you have done
calculations on one - for example, after adding a number of days to a
date. Say you have a struct tm for 2006-05-12. You want to add, for one
reason or another, 21 days to this date. All you have to do is add this
number of days to the tm_mday field of the struct tm - you now have a
struct tm for 2006-05-33! - and pass its address as an argument to
mktime(). You can ignore the resulting time_t in this case - but the
side effect of this call will be that the struct tm is normalised to
2006-06-02. Very handy.

Richard
 
P

pete

Angus said:
Hello

I need to do this conversion but can't seem to find the function.

Angus

N869
7.23.2.3 The mktime function
Synopsis
[#1]
#include <time.h>
time_t mktime(struct tm *timeptr);
Description
[#2] The mktime function converts the broken-down time,
expressed as local time, in the structure pointed to by
timeptr 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 the ranges indicated
above.253) On successful completion, the values of the
tm_wday and tm_yday components of the structure are set
appropriately, and the other components are set to represent
the specified calendar time, but with their values forced to
the ranges indicated above; the final value of tm_mday is
not set until tm_mon and tm_year are determined.
[#3] If the call is successful, a second call to the mktime *
function with the resulting struct tm value shall always
____________________
253Thus, a positive or zero value for tm_isdst causes the
mktime function to presume initially that Daylight Saving
Time, respectively, is or is not in effect for the
specified time. A negative value causes it to attempt to
determine whether Daylight Saving Time is in effect for
the specified time.


leave it unchanged and return the same value as the first
call. Furthermore, if the normalized time is exactly
representable as a time_t value, then the normalized broken-
down time and the broken-down time generated by converting
the result of the mktime function by a call to localtime
shall be identical.
Returns
[#4] The mktime function returns the specified calendar time
encoded as a value of type time_t. If the calendar time
cannot be represented, the function returns the value
(time_t)-1.
[#5] EXAMPLE What day of the week is July 4, 2001?
#include <stdio.h>
#include <time.h>
static const char *const wday[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "-unknown-"
};
struct tm time_str;
/* ... */
time_str.tm_year = 2001 - 1900;
time_str.tm_mon = 7 - 1;
time_str.tm_mday = 4;
time_str.tm_hour = 0;
time_str.tm_min = 0;
time_str.tm_sec = 1;
time_str.tm_isdst = -1;
if (mktime(&time_str) == (time_t)-1)
time_str.tm_wday = 7;
printf("%s\n", wday[time_str.tm_wday]);
 
B

Ben Hetland

Richard said:
mktime(). You can ignore the resulting time_t in this case - but the
side effect of this call will be that the struct tm is normalised to
2006-06-02. Very handy.

Yes, but related to this question:
I often have data sets where the date & time are given as UTC and not
local time. The elements are given separately, such as 'month' and
'hour', so they are straightforward to put into a struct tm.

Since 'mktime()' is not directly usable as it wants to adjust for the
timezone, is there a quick and handy way to do the conversion which is
also portable and standard-compliant?

(Practical solutions often end-up with some dirty tricks or a fair
amount of code to work around the timezone dependency.)
 
G

Gordon Burditt

side effect of this call will be that the struct tm is normalised to
Yes, but related to this question:
I often have data sets where the date & time are given as UTC and not
local time. The elements are given separately, such as 'month' and
'hour', so they are straightforward to put into a struct tm.

Since 'mktime()' is not directly usable as it wants to adjust for the
timezone, is there a quick and handy way to do the conversion which is
also portable and standard-compliant?

Some systems, including FreeBSD, have timegm() which is just like
mktime() except it assumes that the broken-down time is in GMT.
(mktime() undoes localtime() and timegm() undoes gmtime()).
timegm() is *NOT* a standard function while the others mentioned in
this paragraph are.
(Practical solutions often end-up with some dirty tricks or a fair
amount of code to work around the timezone dependency.)

Hacks include determining the time zone offset by:

1. Pick a time near the time of interest, run localtime(), then
mktime() on the result.
2. Use the same time as above, run gmtime(), then mktime() on the
result.
3. Subtract the two time_t's obtained from mktime above in (1) and (2).
This is the time zone offset.
4. Use this to adjust the result of mktime().

I am not sure how well this works around DST changes. It may not provide
consistent results for something like Saudi Arabian solar time.

Gordon L. Burditt
 
J

jjf

Angus said:
I need to do this conversion but can't seem to find the function.

A google search for the term

'struct tm' time_t

gives about 296,000 hits. I didn't check them all, but the first three
each lead more or less directly to the answer.
 
E

Eric Sosman

Gordon Burditt wrote On 05/12/06 15:48,:
Some systems, including FreeBSD, have timegm() which is just like
mktime() except it assumes that the broken-down time is in GMT.
(mktime() undoes localtime() and timegm() undoes gmtime()).
timegm() is *NOT* a standard function while the others mentioned in
this paragraph are.




Hacks include determining the time zone offset by:

1. Pick a time near the time of interest, run localtime(), then
mktime() on the result.
2. Use the same time as above, run gmtime(), then mktime() on the
result.
3. Subtract the two time_t's obtained from mktime above in (1) and (2).
This is the time zone offset.

G.L.B. surely knows this, but others might not: By "subtract"
he doesn't mean "use the `-' operator," because the encoding of
time_t values is implementation-dependent and the arithmetic
difference between two encoded values may be meaningless (even if
it's meaningful, you don't know what it means). Instead, use the
difftime() function: this is part of the library, understands the
library's way of encoding time_t, and picks apart that encoding
to deliver a time delta expressed in floating-point seconds.
4. Use this to adjust the result of mktime().

Another way to do essentially the same thing, but going the
other way around the barn, is to apply both localtime() and
gmtime() to a single time_t value, and use the two `struct tm's
to determine the adjustment. You can then apply that adjustment
to the `struct tm's you'll use when converting the input data
with mktime() later on.
I am not sure how well this works around DST changes. It may not provide
consistent results for something like Saudi Arabian solar time.

Both methods have the same problems with time-varying zone
adjustments. A plausible away to detect that a given conversion
might be wrong would be to use gmtime() to convert it back again,
comparing the result to the original input (but note that mktime()
will perturb the `struct tm' passed to it; keep a copy).
 
B

Ben Hetland

Gordon said:
Some systems, including FreeBSD, have timegm() which is just like
mktime() except it assumes that the broken-down time is in GMT.

This is part of the GCC libraries too, AFAIK. Alas, it is not a
"standard" one. (It should be, IMHO...)

As probably the implementation of mktime() would rely on something
equivalent to timegm() in many cases, it is kind of strange that this
"UTC variant" was left out or "forgotten" in the standard ...

My idea of solving this most efficiently (when I need to use the
conversion _a_lot_) was to simply duplicate the implementation of
timegm() myself, which would save a lot of unnecessary time zone
calculations altogether.

I am not sure how well this works around DST changes.

I did a quick test implementation of your proposed "hack", using CET as
a test case. I chose the "pick a time near the time of interest" as
simply setting the struct tm fields to the UTC values I wanted to
convert, which should be off by less than a day.

It turned out that this was sensitive to the initial choice of the
tm_isdst field, but when set to 0 (=no DST, well it is UTC after all!)
it seemed to work well before, after, and during both DST changes.

It may not provide
consistent results for something like Saudi Arabian solar time.

That I don't know. I guess that would require the initial "guess" of
time to be off by less than the frequency of time changes?


Anyway, to conclude, it is not exactly the "quick and handy way" of a
solution, nor is it very efficient for use in a program that needs this
conversion a lot (even if one hides it all in a subroutine). What it
actually does is to end up doing the convertion several time WITH
timezone calculations. Yuck! (In fact, the current implementation I use
does something similar, but not the same.)

But it seems to work!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top