Time Stuff

G

George

In Time.h there is a structure defined for time settings. I'm
building an embedded system that has a Real Time Clock but it's not PC
compatible.

My question is:

I don't some elements of the structure such as day of the week or day
of the year, but I do know year,month,date,hour,min,sec. Does the
language support filling in the missing elements. And is there a
consistency check for that time structure.

Thanks
George
 
L

Lewis Bowers

George said:
In Time.h there is a structure defined for time settings. I'm
building an embedded system that has a Real Time Clock but it's not PC
compatible.

My question is:

I don't some elements of the structure such as day of the week or day
of the year, but I do know year,month,date,hour,min,sec. Does the
language support filling in the missing elements. And is there a
consistency check for that time structure.

I guess the struct you mention is struct tm. The 6 values you do know are
enough assuming that the date is in range of available dates on the
implementation.
Put the values in the struct and use function mktime to calculate a
calendar
time. The other fields will be normalized.

Example:
#include <stdio.h>
#include <time.h>

int main(void)
{
time_t date;
struct tm t = {0};

/* July 4, 2004 1:00:15 pm */
t.tm_mon = 6; /* July */
t.tm_mday = 4;
t.tm_year = 104; /* Year 2004 */
t.tm_hour = 13; /* 1 pm */
t.tm_min = 0;
t.tm_sec = 15;

date = mktime(&t);
if(date != (time_t)-1)
printf("The date is %s"
"The %d day of the year\n",
ctime(&date), t.tm_yday);
else puts("Time is not available");
return 0;
}
 
G

George

Lewis Bowers said:
I guess the struct you mention is struct tm. The 6 values you do know are
enough assuming that the date is in range of available dates on the
implementation.
Put the values in the struct and use function mktime to calculate a
calendar
time. The other fields will be normalized.

Example:
#include <stdio.h>
#include <time.h>

int main(void)
{
time_t date;
struct tm t = {0};

/* July 4, 2004 1:00:15 pm */
t.tm_mon = 6; /* July */
t.tm_mday = 4;
t.tm_year = 104; /* Year 2004 */
t.tm_hour = 13; /* 1 pm */
t.tm_min = 0;
t.tm_sec = 15;

date = mktime(&t);
if(date != (time_t)-1)
printf("The date is %s"
"The %d day of the year\n",
ctime(&date), t.tm_yday);
else puts("Time is not available");
return 0;
}

Thank you so very much. I was purposely not very clear about some of
the details incase C# had a solution while C did not.

I posted this question in other news groups and all I got was babble
from holy that thou types listing the problems with my question.

Lewis you rock!!!
 
K

kyle york

Greetings,
I posted this question in other news groups and all I got was babble
from holy that thou types listing the problems with my question.

In the other groups you failed to mention a language, architecture, or
implementation making it *very* difficult to answer your question. The
answer would be different in either BASIC or LISP.
 
A

Alan Balmer

I posted this question in other news groups and all I got was babble
from holy that thou types listing the problems with my question.

In fairness, I will point out that one of those newsgroups was
comp.arch.embedded, and the response was that George had not given
enough detail to suggest a solution. In the world of c.a.e., asking
for further information was quite reasonable (as one responder pointed
out, we don't even know if it's a hosted implementation.)

George's response to this request was " If you can't help shut up!!"
 
G

George

Lewis Bowers said:
I guess the struct you mention is struct tm. The 6 values you do know are
enough assuming that the date is in range of available dates on the
implementation.
Put the values in the struct and use function mktime to calculate a
calendar
time. The other fields will be normalized.

Example:
#include <stdio.h>
#include <time.h>

int main(void)
{
time_t date;
struct tm t = {0};

/* July 4, 2004 1:00:15 pm */
t.tm_mon = 6; /* July */
t.tm_mday = 4;
t.tm_year = 104; /* Year 2004 */
t.tm_hour = 13; /* 1 pm */
t.tm_min = 0;
t.tm_sec = 15;

date = mktime(&t);
if(date != (time_t)-1)
printf("The date is %s"
"The %d day of the year\n",
ctime(&date), t.tm_yday);
else puts("Time is not available");
return 0;
}


Yes. If I enter the month, day, year, hour, minute and second into
the tm structure and call mktime() The day of the year, day of the
week and daylight savings time fields are automatically filled in.

The next step is that I would like to know somethings about the next
date. I can take the time_t date from the above example and add
24*60*60 (sec/hr) seconds to it to get a time 24 hours from the first
time.

Next I want to convert the time_t date to a structure. If I call
localtime() I get returned pointer to a tm sturcture and in that
structure is the correct data.

But where is that structure located? If I call localtime() again will
I get a different pointer. If these routines only create one tm
structure ever then I can live with that. If however the run malloc()
to create a structure but never free(), Then I'll run out of ram.

Now I know this might not be strictly a C question but I know experts
such as yourselves have some insight as to what's happening.

Thanks In Advance
George
 
R

Richard Bos

Yes. If I enter the month, day, year, hour, minute and second into
the tm structure and call mktime() The day of the year, day of the
week and daylight savings time fields are automatically filled in.

The next step is that I would like to know somethings about the next
date. I can take the time_t date from the above example and add
24*60*60 (sec/hr) seconds to it to get a time 24 hours from the first
time.

No, you can't. You don't know that time_t is measured in seconds, or
even that it is an integer. All you know is that time_t is "an
arithmetic type capable of representing times". It is allowed to be a
double indicating a fractional Julian Day Number.

What you _can_ do is take your struct tm, add 1 to its tm_day member,
and then call mktime() again. It will return a time_t, but as a side
effect it will "normalise" your struct tm, bringing its members into the
expected range. You _could_ even try to add 24*60*60 to the tm_sec
member, but that will fail on systems with 16-bit ints... so better
stick to tm_day.
Next I want to convert the time_t date to a structure. If I call
localtime() I get returned pointer to a tm sturcture and in that
structure is the correct data.

But where is that structure located?

Who knows? That's up to the implementation.
If I call localtime() again will I get a different pointer.

This is not guaranteed. According to n869.txt, 7.23.3:

# Execution of any of the functions that return a pointer to one of
# these object types may overwrite the information in any object of the
# same type pointed to by the value returned from any previous call to
# any of them.

Note: "may", not "must".
If these routines only create one tm structure ever then I can live with that.

I expect that they usually do (for starters, it's the easier option),
but...
If however the run malloc() to create a structure but never free(),
Then I'll run out of ram.

....even if they don't, I don't think they'd be used a lot if they leaked
memory left, right, and centre. mktime() is no different in this regard
from, say, strerror().

Richard
 
L

Lewis Bowers

George said:
Yes. If I enter the month, day, year, hour, minute and second into
the tm structure and call mktime() The day of the year, day of the
week and daylight savings time fields are automatically filled in.

The next step is that I would like to know somethings about the next
date. I can take the time_t date from the above example and add
24*60*60 (sec/hr) seconds to it to get a time 24 hours from the first
time.

Next I want to convert the time_t date to a structure. If I call
localtime() I get returned pointer to a tm sturcture and in that
structure is the correct data.

But where is that structure located? If I call localtime() again will
I get a different pointer. If these routines only create one tm
structure ever then I can live with that. If however the run malloc()
to create a structure but never free(), Then I'll run out of ram.

Now I know this might not be strictly a C question but I know experts
such as yourselves have some insight as to what's happening.

I am not sure of your requirements but if it will allow you to declare a struct
and all you need is two calendar dates, ex. current and next day, then all you
need is to declare one tm struct and two time_t values. Dynamic allocations
may not be neccessary.

Example:
#include <stdio.h>
#include <time.h>

int main(void)
{
time_t date,nextdate;
struct tm t;

/* July 4, 2004 1:00:15 pm */
t.tm_mon = 6; /* July */
t.tm_mday = 4;
t.tm_year = 104; /* Year 2004 */
t.tm_hour = 13; /* 1 pm */
t.tm_min = 0;
t.tm_sec = 15;

date = mktime(&t);
if(date != (time_t)-1)
{
printf("The date is %s"
"The %d day of the year\n",
ctime(&date), t.tm_yday);
t.tm_hour += 24;
nextdate = mktime(&t);
if(nextdate != (time_t)-1)
{
printf("\nThe next day is %s"
"The %d day of the year\n",
ctime(&nextdate), t.tm_yday);
printf("\nThere are %.0f secs difference"
" between the two dates\n",
difftime(nextdate,date));
}
else puts("No time available for the next date");
}
else puts("No time available for date");
return 0;
}
 
L

LibraryUser

Alan said:
In fairness, I will point out that one of those newsgroups was
comp.arch.embedded, and the response was that George had not
given enough detail to suggest a solution. In the world of
c.a.e., asking for further information was quite reasonable (as
one responder pointed out, we don't even know if it's a hosted
implementation.)

George's response to this request was " If you can't help shut
up!!"

Obviously a student of Dale Carnegies "How to Win Friends and
Influence People". He will go far, into the plonk pit.
 
G

Gordon Burditt

I guess the struct you mention is struct tm. The 6 values you do know are
I believe you are really supposed to initialize tm_isdst also before
feeding the struct tm to mktime(). 0 is normally a pretty good value, unless
you're dealing with something like logs around the time of a daylight-savings-time
transition, where you can have two occurrences of the time without the timezone
specifier being considered.

Yes. If I enter the month, day, year, hour, minute and second into
the tm structure and call mktime() The day of the year, day of the
week and daylight savings time fields are automatically filled in.

The next step is that I would like to know somethings about the next
date. I can take the time_t date from the above example and add
24*60*60 (sec/hr) seconds to it to get a time 24 hours from the first
time.

No, you are not guaranteed to be able to do any type of math on a
time_t. A time_t is not guaranteed to be of the form "number of
<time unit> since <epoch>". As a horrible example, consider the
following format:

HHmmSSMMDDYYYYY

HH = hour (0-23)
mm = minute (0-59)
SS = second (0-61) [*]
MM = month (1-12)
DD = day (1-31)
YYYYY = year (Y100K problem!)

[*] wierdness here due to leap seconds

fill in the values with decimal digits, now treat it as a decimal
integer. Try fiddling with this, and you realize that subtracting
these gives complete mush (you can't even do a comparison to figure
out which time is earlier, as 15:01 is "earlier" than 15:02 regardless
of what century it's in.)

Try subtracting 1 second (or 1000000000) from 000000010102004 and
see what you get. You SHOULD get 235959123102003 if you really
subtracted 1 second (I'm assuming this particular time did not have
any leap seconds without looking it up), but you won't.

There is no good way to portably add 24 hours to a timestamp, when
you want to talk about the PASSAGE OF TIME, not WHAT THE CLOCK
READS. These differ when you cross a daylight-savings-time transition
or a leap second. 15:00 on consecutive days may be 23 or 25 hours
apart. Adding 1 to tm_day or adding 24 to tm_hour works most of
the time. Then again, even a stopped clock reads correctly twice
a day.

MS-DOS file stamps are not too unlike this (using bit fields to
represent year, month, day, hour, minute, and seconds divided by
two within a 32-bit integer), although at least they put the
high-order time elements in the high-order part of the integer, so
you actually can compare time stamps using > or < .
Next I want to convert the time_t date to a structure. If I call
localtime() I get returned pointer to a tm sturcture and in that
structure is the correct data.
But where is that structure located?

The structure returned by localtime() is static data that may be
overwritten on a subsequent call. This is specified by ANSI C and
should be in any decent documentation of localtime(). (If you write
functions like this, you'd better also carefully document this.)
When in doubt MAKE A COPY OF IT (the structure, not the pointer).
You do NOT have to allocate your copy with malloc() when an auto
variable will do.
If I call localtime() again will
I get a different pointer.

This is not specified. localtime() could play tricks with rotating
several buffers. Or, more commonly, it could return the same pointer
every time.
If these routines only create one tm
structure ever then I can live with that.
If however the run malloc()
to create a structure but never free(), Then I'll run out of ram.

You must not free() the struct tm returned by localtime().

Gordon L. Burditt
 
K

Keith Thompson

SS = second (0-61) [*] [...]
[*] wierdness here due to leap seconds

To allow for leap seconds, you only need 0-60; if we ever need two
leap seconds in the same minute, it will be time to set up the big
equatorial rockets. (C90's struct tm specified 0-61; C99 corrected
this to 0-60.)
 
G

George

No, you can't. You don't know that time_t is measured in seconds, or
even that it is an integer. All you know is that time_t is "an
arithmetic type capable of representing times". It is allowed to be a
double indicating a fractional Julian Day Number.

Interesting. Since t_time Time is seconds past some starting date, I
added 24 hours worth of seconds and then called localtime to generate
a structure from Time.

What you _can_ do is take your struct tm, add 1 to its tm_day member,
and then call mktime() again. It will return a time_t, but as a side
effect it will "normalise" your struct tm, bringing its members into the
expected range. You _could_ even try to add 24*60*60 to the tm_sec
member, but that will fail on systems with 16-bit ints... so better
stick to tm_day.
I was thinking of your solution but worried that that changing say
Sept 30 to Sept 31 (which is an illegal date) would be properly
handled. I understand what you're suggesting and will test that
approach. I'm starting with Borland's BuilderX on WIN XP and only
writing C code for now. My target is the Altera NIOS II (Arm).
Testing is so much faster and easier on the PC.
Who knows? That's up to the implementation.


This is not guaranteed. According to n869.txt, 7.23.3:

# Execution of any of the functions that return a pointer to one of
# these object types may overwrite the information in any object of the
# same type pointed to by the value returned from any previous call to
# any of them.

Note: "may", not "must".


I expect that they usually do (for starters, it's the easier option),
but...


...even if they don't, I don't think they'd be used a lot if they leaked
memory left, right, and centre. mktime() is no different in this regard
from, say, strerror().

I'm creating a scheduling system. Some outputs will be scheduled by
Day-Month-Hour and repeat yearly. Other outputs will be scheduled by
DayofWeek-Hour-Minute and be run daily. The Day-Month is straight
forward. The DayofWeek-Hour-Minute requires me to create an event for
today and an event for toworrow and every day there after. So
unfortunately I'm planning to call these routines a lot. A typical
system will contain 500 schedule entries.

So looks like I need to test for calculation of tomorrows date and
test to see if caling mktime() and localtime() leaks memory. THis
will have to wait till next week but I'll report the results here.

Thanks
George
 
G

George

I believe you are really supposed to initialize tm_isdst also before
feeding the struct tm to mktime(). 0 is normally a pretty good value, unless
you're dealing with something like logs around the time of a daylight-savings-time
transition, where you can have two occurrences of the time without the timezone
specifier being considered.

Yes. If I enter the month, day, year, hour, minute and second into
the tm structure and call mktime() The day of the year, day of the
week and daylight savings time fields are automatically filled in.

The next step is that I would like to know somethings about the next
date. I can take the time_t date from the above example and add
24*60*60 (sec/hr) seconds to it to get a time 24 hours from the first
time.

No, you are not guaranteed to be able to do any type of math on a
time_t. A time_t is not guaranteed to be of the form "number of
<time unit> since <epoch>". As a horrible example, consider the
following format:

HHmmSSMMDDYYYYY

HH = hour (0-23)
mm = minute (0-59)
SS = second (0-61) [*]
MM = month (1-12)
DD = day (1-31)
YYYYY = year (Y100K problem!)

[*] wierdness here due to leap seconds

fill in the values with decimal digits, now treat it as a decimal
integer. Try fiddling with this, and you realize that subtracting
these gives complete mush (you can't even do a comparison to figure
out which time is earlier, as 15:01 is "earlier" than 15:02 regardless
of what century it's in.)

Try subtracting 1 second (or 1000000000) from 000000010102004 and
see what you get. You SHOULD get 235959123102003 if you really
subtracted 1 second (I'm assuming this particular time did not have
any leap seconds without looking it up), but you won't.

There is no good way to portably add 24 hours to a timestamp, when
you want to talk about the PASSAGE OF TIME, not WHAT THE CLOCK
READS. These differ when you cross a daylight-savings-time transition
or a leap second. 15:00 on consecutive days may be 23 or 25 hours
apart. Adding 1 to tm_day or adding 24 to tm_hour works most of
the time. Then again, even a stopped clock reads correctly twice
a day.

MS-DOS file stamps are not too unlike this (using bit fields to
represent year, month, day, hour, minute, and seconds divided by
two within a 32-bit integer), although at least they put the
high-order time elements in the high-order part of the integer, so
you actually can compare time stamps using > or < .
Next I want to convert the time_t date to a structure. If I call
localtime() I get returned pointer to a tm sturcture and in that
structure is the correct data.
But where is that structure located?

The structure returned by localtime() is static data that may be
overwritten on a subsequent call. This is specified by ANSI C and
should be in any decent documentation of localtime(). (If you write
functions like this, you'd better also carefully document this.)
When in doubt MAKE A COPY OF IT (the structure, not the pointer).
You do NOT have to allocate your copy with malloc() when an auto
variable will do.
If I call localtime() again will
I get a different pointer.

This is not specified. localtime() could play tricks with rotating
several buffers. Or, more commonly, it could return the same pointer
every time.
If these routines only create one tm
structure ever then I can live with that.
If however the run malloc()
to create a structure but never free(), Then I'll run out of ram.

You must not free() the struct tm returned by localtime().

Gordon L. Burditt


Wow. Information overload!!! I understand all that you said except.
Try subtracting 1 second (or 1000000000) from 000000010102004 and
see what you get. You SHOULD get 235959123102003 if you really
subtracted 1 second (I'm assuming this particular time did not have
any leap seconds without looking it up), but you won't.

What does 000000010102004 represent and why is 1000000000 one second?
They don't look like time_t values.

The routine difftime() performs math (subtraction?) on two time_t
parameters. Do you think that routine take into consideration all
that you point out??

I'm out of town till next week. I'll start testing and report the
results.

Thanks
George
 
K

Keith Thompson

(e-mail address removed) (Richard Bos) wrote in message


Interesting. Since t_time Time is seconds past some starting date, I
added 24 hours worth of seconds and then called localtime to generate
a structure from Time.

I think you missed the point. The type time_t may happen to represent
seconds past some starting date on your system, but the C standard
only guarantees that it's "an arithmetic type capable of representing
times". Adding 86400 to a time_t may advance it by 1 day on your
system; on another system, it could add 86400 days, or it could go
backwards.

If you're sure that your code will never be ported to a system with a
different time_t representation, you can get away with doing
arithmetic on time_t values, but it's not portable.
So looks like I need to test for calculation of tomorrows date and
test to see if caling mktime() and localtime() leaks memory. THis
will have to wait till next week but I'll report the results here.

mktime() and localtime() don't leak memory; if they do, it's a bug in
your library implementation. localtime() returns a pointer to a
static object.
 
R

Richard Bos

(e-mail address removed) (George) wrote:

[ Please! Learn to snip... ]
No, you are not guaranteed to be able to do any type of math on a
time_t. A time_t is not guaranteed to be of the form "number of
<time unit> since <epoch>". As a horrible example, consider the
following format:

HHmmSSMMDDYYYYY

HH = hour (0-23)
mm = minute (0-59)
SS = second (0-61) [*]
MM = month (1-12)
DD = day (1-31)
YYYYY = year (Y100K problem!)

That is indeed evil. Everybody knows it should be HHmmSSDDMMYYYYY :p
What does 000000010102004 represent and why is 1000000000 one second?
They don't look like time_t values.

Read them in the light of the example Gordon gave.

HHmmSSMMDDYYYYY
000000010102004 == 2004/01/01, 00:00:00
1000000000 == 0000/00/00, 00:00:01
235959123102003 == 2003/12/31, 23:59:59
-989897996
So subtracting 1000000000 from 000000010102004 would have got you
235959123102003 if it really subtracted one second; but since time_t is
a simple arithmetic type, what it _will_ get you is -989897996, which
could be 97996 BC/98/98, 00:00:00, or perhaps even 281473986812660,
which is 12660/98/68, 28:14:73...
The routine difftime() performs math (subtraction?) on two time_t
parameters. Do you think that routine take into consideration all
that you point out??

It'd better. That's its job. Note: it does not perform _integer_ math on
the time_t's. It calculates the difference _in seconds_.

Richard
 

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,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top