473,465 Members | 1,889 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Date Arithmetic

Are there any localized facilites for performing date arithmetic that
properly considers leap years, daylight savings time, and whatever
other peculiarities of the gregorian lunar calendar?

Specifically, considering the following program and it's output below
can someone provide a suitable body for the time_subtract function?

Mike

--8<-- program

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

time_t *
time_subtract(time_t *timep, struct tm *adj)
{
/* ???? */
}

int
main(int argc, char *argv[])
{
struct tm adj;
time_t now;
time_t *time3hoursago;

memset(&adj, 0, sizeof adj);
adj.tm_hour = 3; /* 3 hours, not 3rd hour */
now = time(NULL);
time3hoursago = time_subtract(&now, &adj);
puts(ctime(time3hoursago));

return EXIT_SUCCESS;
}

--8<-- output

$ date
Sat Nov 1 02:36:09 EST 2003
$ ./time_sub
Fri Oct 31 23:36:09 2003
Nov 13 '05 #1
12 9801
"Michael B Allen" <mb*****@ioplex.com> wrote in message
news:pa**********************************@ioplex.c om...
Are there any localized facilites for performing date arithmetic that
properly considers leap years, daylight savings time, and whatever
other peculiarities of the gregorian lunar calendar?

Specifically, considering the following program and it's output below
can someone provide a suitable body for the time_subtract function?

Mike

--8<-- program

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

time_t *
time_subtract(time_t *timep, struct tm *adj)
{
/* ???? */ time_t t = mktime(adj);
return difftime(*timep, t) }

int
main(int argc, char *argv[])
{
struct tm adj;
time_t now;
time_t *time3hoursago;

memset(&adj, 0, sizeof adj);
adj.tm_hour = 3; /* 3 hours, not 3rd hour */
now = time(NULL);
time3hoursago = time_subtract(&now, &adj);
puts(ctime(time3hoursago));

return EXIT_SUCCESS;
}

--8<-- output

$ date
Sat Nov 1 02:36:09 EST 2003
$ ./time_sub
Fri Oct 31 23:36:09 2003


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

time_t offset_hours(const time_t *t, int hours)
{
struct tm *cal = localtime(t);
cal->tm_hour += hours;
return mktime(cal);
}

int main()
{
time_t now;
time_t other;
int offset = -3;

now = time(NULL);
other = offset_hours(&now, offset);

printf("%s", asctime(localtime(&now)));
printf(" offset by %d hours is\n", offset);
printf("%s", asctime(localtime(&other)));

return 0;
}
-Mike


Nov 13 '05 #2
"Mike Wahler" <mk******@mkwahler.net> wrote in message
news:fb******************@newsread4.news.pas.earth link.net...
time_subtract(time_t *timep, struct tm *adj)
{
/* ???? */

time_t t = mktime(adj);
return difftime(*timep, t)


Ignore this part. It was just me (not) "thinking out loud". :-)

-Mike
Nov 13 '05 #3
On Fri, 31 Oct 2003 23:47:53 -0500, in comp.lang.c , Michael B Allen
<mb*****@ioplex.com> wrote:
Are there any localized facilites for performing date arithmetic that
properly considers leap years, daylight savings time, and whatever
other peculiarities of the gregorian lunar calendar?
No, but they're easy to write. For instance since we know that the
year 1900 is a leap-year, we can trivially determine the number of
days between any two dates stored in a struct tm. Extending this to
larger ranges is also relatively simple, provider you don't want to go
back before the Great Calendar Change, or past the next one. If you
want to consider leap-seconds its much more fiddly.
Specifically, considering the following program and it's output below
can someone provide a suitable body for the time_subtract function?


You can probably just subtract the various members of a struct tm from
each other. Many implementations of struct tm renormalise the elements
after arithmetic.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Nov 13 '05 #4
On Sat, 01 Nov 2003 02:22:51 -0500, Mike Wahler wrote:
time_t offset_hours(const time_t *t, int hours) {
struct tm *cal = localtime(t);
cal->tm_hour += hours;
return mktime(cal);
}
Well this is sort of what I want but more generally like this:

time_t
time_offset(const time *t, struct tm *adj)
{
unsigned long secs = (unsigned long)*t; /* ? */

secs += adj->tm_sec;
secs += adj->tm_min * 60;
secs += adj->tm_hour * 60 * 60;
secs += adj->tm_mday * 24 * 60 * 60;
secs += adj->tm_mon * 30 * 24 * 60 * 60;
secs += adj->tm_year * 12 * 30 * 24 * 60 * 60;

return secs;
}

but with proper consideration for the number of days in a month, leap
seconds, DST, etc...

int main()
{
time_t now;
time_t other;
int offset = -3;

now = time(NULL);
other = offset_hours(&now, offset);

printf("%s", asctime(localtime(&now))); printf(" offset by %d hours
is\n", offset); printf("%s", asctime(localtime(&other)));

return 0;
}
-Mike

Nov 13 '05 #5
"Mark McIntyre" <ma**********@spamcop.net> wrote in message
news:65********************************@4ax.com...
On Fri, 31 Oct 2003 23:47:53 -0500, in comp.lang.c , Michael B Allen
<mb*****@ioplex.com> wrote:
Are there any localized facilites for performing date arithmetic that
properly considers leap years, daylight savings time, and whatever
other peculiarities of the gregorian lunar calendar?
No, but they're easy to write.


Daylight savings time adds a whole heap of difficulty.
For instance since we know that the year 1900 is a leap-year,
Err, no it isn't (or rather, wasn't).
we can trivially determine the number of days between any two dates
stored in a struct tm.


Dates aren't much of a problem. Times are.
Specifically, considering the following program and it's output below
can someone provide a suitable body for the time_subtract function?


You can probably just subtract the various members of a struct tm from
each other. Many implementations of struct tm renormalise the elements
after arithmetic.


I believe this is required of mktime(), but not of any of the other related
functions. Unless I'm missing something (and if I am, I hope someone will
point it out), this means there is no portable method of calculating a new
GMT time from a GMT time and an offset.

Alex
Nov 13 '05 #6
"Michael B Allen" <mb*****@ioplex.com> wrote in message
news:pa**********************************@ioplex.c om...
On Sat, 01 Nov 2003 02:22:51 -0500, Mike Wahler wrote:
time_t offset_hours(const time_t *t, int hours) {
struct tm *cal = localtime(t);
cal->tm_hour += hours;
return mktime(cal);
}
Well this is sort of what I want but more generally like this:

time_t
time_offset(const time *t, struct tm *adj)

^^^^ ITYM time_t {
unsigned long secs = (unsigned long)*t; /* ? */
It is not guaranteed that time_t holds a number of seconds (although it
often does), so this doesn't quite cut it.
secs += adj->tm_sec;
secs += adj->tm_min * 60;
secs += adj->tm_hour * 60 * 60;
secs += adj->tm_mday * 24 * 60 * 60;
secs += adj->tm_mon * 30 * 24 * 60 * 60;
secs += adj->tm_year * 12 * 30 * 24 * 60 * 60;

return secs;
}

but with proper consideration for the number of days in a month, leap
seconds, DST, etc...


AIUI, leap seconds are basically impossible to handle (because they are
added as required, not on a regular basis - a quick web search seemed to
confirm this). But the two implementations I tested seemed to correctly
handle the other aspects:

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

time_t time_offset(const time_t *base, const struct tm *off) {
struct tm *t;

t = localtime(base);
if (!t) return (time_t)(-1);

t->tm_sec += off->tm_sec;
t->tm_min += off->tm_min;
t->tm_hour += off->tm_hour;
t->tm_mday += off->tm_mday;
t->tm_mon += off->tm_mon;
t->tm_year += off->tm_year;

return mktime(t);
}

int main(void) {
time_t now = time(0);
struct tm off = {0};
time_t new;

printf("local time now: %s", ctime(&now));

off.tm_hour = -23;
new = time_offset(&now, &off);
printf("local time 23 hours ago: %s", ctime(&new));

off.tm_hour = 0;
off.tm_mday = -20;
new = time_offset(&now, &off);
printf("local time 20 days ago: %s", ctime(&new));

return 0;
}

Output:
local time now: Sat Nov 1 11:19:53 2003
local time 23 hours ago: Fri Oct 31 12:19:53 2003
local time 20 days ago: Sun Oct 12 12:19:53 2003

(The last is correct due to the end of BST last week, here in the UK.)

Alex
Nov 13 '05 #7

"Michael B Allen" <mb*****@ioplex.com> wrote in message
news:pa**********************************@ioplex.c om...
On Sat, 01 Nov 2003 02:22:51 -0500, Mike Wahler wrote:
time_t offset_hours(const time_t *t, int hours) {
struct tm *cal = localtime(t);
cal->tm_hour += hours;
return mktime(cal);
}
Well this is sort of what I want but more generally like this:

time_t
time_offset(const time *t, struct tm *adj)
{
unsigned long secs = (unsigned long)*t; /* ? */

secs += adj->tm_sec;
secs += adj->tm_min * 60;
secs += adj->tm_hour * 60 * 60;
secs += adj->tm_mday * 24 * 60 * 60;
secs += adj->tm_mon * 30 * 24 * 60 * 60;
secs += adj->tm_year * 12 * 30 * 24 * 60 * 60;

return secs;
}


Note that 'time_t' does not necessarily represent seconds.

but with proper consideration for the number of days in a month, leap
seconds, DST, etc...


The code I posted does that.

-Mike
Nov 13 '05 #8
On Sat, 01 Nov 2003 06:26:39 -0500, Alex Fraser wrote:
#include <stdio.h>
#include <time.h>

time_t time_offset(const time_t *base, const struct tm *off) {
struct tm *t;

t = localtime(base);
if (!t) return (time_t)(-1);

t->tm_sec += off->tm_sec;
t->tm_min += off->tm_min;


What happends if t->tm_min is 55 and off->tm_min 25? That will result in
t->tm_min being 80. I didn't think this (nor Mike's code) would work
because of this. No?

Mike
Nov 13 '05 #9
On Sat, 01 Nov 2003 06:01:09 -0500, Alex Fraser wrote:
You can probably just subtract the various members of a struct tm from
each other. Many implementations of struct tm renormalise the elements
after arithmetic.


I believe this is required of mktime(), but not of any of the other
related functions. Unless I'm missing something (and if I am, I hope
someone will point it out), this means there is no portable method of
calculating a new GMT time from a GMT time and an offset.


I can see glibc does this but the standard just reads:

....and the original values of the other components are not restricted to
the ranges indicated above.267)

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

and note 267 reads:

267) Thus, 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 neg ative value causes it to
attempt to determine whether Daylight Saving Time is in effect for the
specified time.

The POSIX standard is virtually identical of course. So does tm->tm_min +=
200; mktime(tm) mean the time will be advanced by 200 * 60 seconds or by
the truncated remainder (i.e. 20 seconds)?

Mike
Nov 13 '05 #10
"Michael B Allen" <mb*****@ioplex.com> wrote in message
news:pa**********************************@ioplex.c om...
On Sat, 01 Nov 2003 06:01:09 -0500, Alex Fraser wrote:
Many implementations of struct tm renormalise the elements
after arithmetic.


I believe this is required of mktime(), [...]


I can see glibc does this but the standard just reads:

...and the original values of the other components are not restricted to
the ranges indicated above.267)

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

and note 267 reads:

267) [you can set tm_isdst < 0 and mktime() will try to work it out]

The POSIX standard is virtually identical of course. So does
tm->tm_min += 200; mktime(tm) mean the time will be advanced by 200 * 60
seconds or by the truncated remainder (i.e. 20 seconds)?


The statement "the final value of tm_mday is not set until tm_mon and
tm_year are determined" makes a lot more sense if the latter is the case,
and you assume the same logic applies to all members. But I would hope there
was something more explicit somewhere in the standard...

Alex
Nov 13 '05 #11
On Sat, 1 Nov 2003 11:01:09 -0000, in comp.lang.c , "Alex Fraser"
<me@privacy.net> wrote:
"Mark McIntyre" <ma**********@spamcop.net> wrote in message
news:65********************************@4ax.com.. .
On Fri, 31 Oct 2003 23:47:53 -0500, in comp.lang.c , Michael B Allen
<mb*****@ioplex.com> wrote:
>Are there any localized facilites for performing date arithmetic that
>properly considers leap years, daylight savings time, and whatever
>other peculiarities of the gregorian lunar calendar?
No, but they're easy to write.


Daylight savings time adds a whole heap of difficulty.


Only you're worrying about places that don't/didn't observe it via a
rule.
For instance since we know that the year 1900 is a leap-year,


Err, no it isn't (or rather, wasn't).


that should indeed have read isn't".
we can trivially determine the number of days between any two dates
stored in a struct tm.


Dates aren't much of a problem. Times are.


Never had a problem with them myself. Unfortunately the date/time
algos I've written are owned by my employer but really, I've found it
pretty easy.
>Specifically, considering the following program and it's output below
>can someone provide a suitable body for the time_subtract function?


You can probably just subtract the various members of a struct tm from
each other. Many implementations of struct tm renormalise the elements
after arithmetic.


I believe this is required of mktime(), but not of any of the other related
functions. Unless I'm missing something (and if I am, I hope someone will
point it out), this means there is no portable method of calculating a new
GMT time from a GMT time and an offset.


Quite probably.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Nov 13 '05 #12
"Mark McIntyre" <ma**********@spamcop.net> wrote in message
news:0c********************************@4ax.com...
On Sat, 1 Nov 2003 11:01:09 -0000, in comp.lang.c , "Alex Fraser"
<me@privacy.net> wrote:
"Mark McIntyre" <ma**********@spamcop.net> wrote in message
news:65********************************@4ax.com.. .
On Fri, 31 Oct 2003 23:47:53 -0500, in comp.lang.c , Michael B Allen
<mb*****@ioplex.com> wrote:
>Are there any localized facilites for performing date arithmetic that
>properly considers leap years, daylight savings time, and whatever
>other peculiarities of the gregorian lunar calendar?

No, but they're easy to write.


Daylight savings time adds a whole heap of difficulty.


Only you're worrying about places that don't/didn't observe it via a
rule.


There's not much you can do if there's no rule. I was actually thinking of
the difficulty of handling the various rules for finding the dates, and (in
particular) handling the change time correctly, although the latter is
easily generalised. Tricky might be a more accurate description than
difficult, it's very easy to get wrong.

I still don't understand why there's no "time_t mkgmtime(struct tm *)"
(counterpart of mktime()) and/or "time_t addtime(time_t, double)"
(counterpart of difftime()) though...

Alex
Nov 13 '05 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: gsv2com | last post by:
Maybe I'm tired, but I'm having a small problem with a date function I'm writing. Total noobish I know, but this is just going beyond me for some reason... What I want to happen is send a date...
9
by: shoba | last post by:
hi i'm provided with time in seconds. this is the time elapsed from the midnight to jan 1970 till certain date. i would like to know how to determine that date using this time thanks in...
7
by: Mick White | last post by:
According to the Safari browser the world began on "Fri Dec 13 1901 15:45:52 GMT-0500", but I need to be able to get around this limitation. I am interested in dates from 1500 to 1901, as far as...
1
by: Gil | last post by:
I run a webserver on Win2k Server and program in vb.net. I am trying to perform a calculation that results in two weeks of data given any selected date that starts with the Sunday of the...
0
by: Howard Hinnant | last post by:
I'm tossing my date class into the public domain because I'm tired of it sitting around gathering dust. It was first created over a decade ago and has been evolving by bits and pieces since then....
15
by: Donkey | last post by:
Hi, The precision of built-in date type of C is very low. Even using long double float type or double float type, we can only use 12 or 16 digits after the decimal point. What can we do if we want...
335
by: extrudedaluminiu | last post by:
Hi, Is there any group in the manner of the C++ Boost group that works on the evolution of the C language? Or is there any group that performs an equivalent function? Thanks, -vs
7
by: mr.nimz | last post by:
hello, this is antenio. recently i've come to a problem. i got a way through it, somehow, still it left me in a curious state, so i'm posting it here, if i can get an answer from some techy, ...
4
by: thomasc1020 | last post by:
This is regarding VB.NET 2003. Variable 'Date' is a string and it contains date information in this format: "DEC/05/2007". Now I am trying to convert the format as "2007-12-05". Is it...
6
by: Geoff Cox | last post by:
Hello, at the moment I can add the combined date and time into MySQL using php $dt1 = date("Y-m-d H:i:s"); is it possible to add the date and time separately? I thought it might be
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.