Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #28980 > unrolled thread
| Started by | Anders Wegge Keller <wegge@wegge.dk> |
|---|---|
| First post | 2012-12-06 15:25 +0100 |
| Last post | 2012-12-09 08:41 -0800 |
| Articles | 20 on this page of 28 — 9 participants |
Back to article view | Back to comp.lang.c
mktime Anders Wegge Keller <wegge@wegge.dk> - 2012-12-06 15:25 +0100
Re: mktime James Kuyper <jameskuyper@verizon.net> - 2012-12-06 09:53 -0500
Re: mktime Eric Sosman <esosman@comcast-dot-net.invalid> - 2012-12-06 10:11 -0500
Re: mktime Anders Wegge Keller <wegge@wegge.dk> - 2012-12-06 17:40 +0100
Re: mktime Eric Sosman <esosman@comcast-dot-net.invalid> - 2012-12-06 14:20 -0500
Re: mktime Keith Thompson <kst-u@mib.org> - 2012-12-06 12:28 -0800
Re: mktime Eric Sosman <esosman@comcast-dot-net.invalid> - 2012-12-06 17:36 -0500
Re: mktime Eric Sosman <esosman@comcast-dot-net.invalid> - 2012-12-06 17:42 -0500
Re: mktime Keith Thompson <kst-u@mib.org> - 2012-12-06 12:20 -0800
Re: mktime Anders Wegge Keller <wegge@wegge.dk> - 2012-12-06 21:37 +0100
Re: mktime "Heinrich Wolf" <invalid@invalid.invalid> - 2012-12-07 09:48 +0100
Re: mktime James Kuyper <jameskuyper@verizon.net> - 2012-12-07 08:08 -0500
Re: mktime "christian.bau" <christian.bau@cbau.wanadoo.co.uk> - 2012-12-07 09:23 -0800
Re: mktime James Kuyper <jameskuyper@verizon.net> - 2012-12-07 13:14 -0500
Re: mktime Eric Sosman <esosman@comcast-dot-net.invalid> - 2012-12-07 13:46 -0500
Re: mktime "Heinrich Wolf" <invalid@invalid.invalid> - 2012-12-07 19:59 +0100
Re: mktime Robert Wessel <robertwessel2@yahoo.com> - 2012-12-07 15:50 -0600
Re: mktime "Heinrich Wolf" <invalid@invalid.invalid> - 2012-12-07 21:39 +0100
Re: mktime Eric Sosman <esosman@comcast-dot-net.invalid> - 2012-12-07 17:17 -0500
Re: mktime Keith Thompson <kst-u@mib.org> - 2012-12-07 17:50 -0800
Re: mktime Eric Sosman <esosman@comcast-dot-net.invalid> - 2012-12-08 08:34 -0500
Re: mktime pacman@kosh.dhis.org (Alan Curry) - 2012-12-07 22:44 +0000
Re: mktime "Heinrich Wolf" <invalid@invalid.invalid> - 2012-12-08 10:31 +0100
Re: mktime pacman@kosh.dhis.org (Alan Curry) - 2012-12-08 20:50 +0000
Re: mktime "Heinrich Wolf" <invalid@invalid.invalid> - 2012-12-09 11:39 +0100
Re: mktime pacman@kosh.dhis.org (Alan Curry) - 2012-12-09 19:47 +0000
Re: mktime "Heinrich Wolf" <invalid@invalid.invalid> - 2012-12-10 09:51 +0100
Re: mktime sla29970@gmail.com - 2012-12-09 08:41 -0800
Page 1 of 2 [1] 2 Next page →
| From | Anders Wegge Keller <wegge@wegge.dk> |
|---|---|
| Date | 2012-12-06 15:25 +0100 |
| Subject | mktime |
| Message-ID | <87vccf1clw.fsf@huddi.jernurt.dk> |
According to the C2011 draft I have available, the values in the struct tm, passed to mktime(), are not restricted to the normalized ranges. (2.27.2.3 §2). Is this to be taken literally, such that any combination of values in the tm struct, that corresponds to something that can be expressed in a time_t is a valid input? As I read the following paragrahp, that seem to be the case. Which lead me to think of exxtreme cases like tm_sec, tm_min, tm_hour, tm_mday and tm_mon all at INT_MAX, and tm_year set to a sufficiently large negative value. Am I missing something, or would a conforming implementation have to handle this? -- /Wegge Leder efter redundant peering af dk.*,linux.debian.*
[toc] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2012-12-06 09:53 -0500 |
| Message-ID | <k9qbgr$ofj$1@dont-email.me> |
| In reply to | #28980 |
On 12/06/2012 09:25 AM, Anders Wegge Keller wrote: > > According to the C2011 draft I have available, the values in the > struct tm, passed to mktime(), are not restricted to the normalized > ranges. (2.27.2.3 §2). > > Is this to be taken literally, such that any combination of values in > the tm struct, that corresponds to something that can be expressed in > a time_t is a valid input? Yes. This feature, allows performance of date arithmetic. For instance, take a struct tm that represents 2012-12-06 09:41, subtract 7 from tm_mday, and pass it to mktime(), which should normalize that struct to describe 2012-11-29 09:41. This is, in fact, the main thing I've ever used mktime() for. mktime() has to know how many days there are in each month, which years are leap years, what day of the week each date is; so it saves me from having to write all that logic in my own code. > As I read the following paragrahp, that seem to be the case. Which > lead me to think of exxtreme cases like tm_sec, tm_min, tm_hour, > tm_mday and tm_mon all at INT_MAX, and tm_year set to a sufficiently > large negative value. > > Am I missing something, or would a conforming implementation have to > handle this? Yes, it would. -- James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2012-12-06 10:11 -0500 |
| Message-ID | <k9qcil$oh$1@dont-email.me> |
| In reply to | #28980 |
On 12/6/2012 9:25 AM, Anders Wegge Keller wrote:
>
> According to the C2011 draft I have available, the values in the
> struct tm, passed to mktime(), are not restricted to the normalized
> ranges. (2.27.2.3 §2).
ITYM 7.27.2.3.
> Is this to be taken literally,
That's the usual way to take normative text ...
> such that any combination of values in
> the tm struct, that corresponds to something that can be expressed in
> a time_t is a valid input?
Yes, keeping in mind that time_t's range is implementation-
defined (7.27.1p4). If the tm_xxx values correspond to a time_t
value in that implementation-defined range, 7.27.2.3p3 requires
mktime() to return that time_t value.
Clearly, the intent is to relieve the programmer of the burden
of all that date arithmetic. If you've got a struct tm representing
some time T and you want to determine the time at T plus 01:23:45,
you can blithely add 1*3600+23*60+45 to the tm_sec field and call
mktime(), and mktime() will figure things out.
> As I read the following paragrahp, that seem to be the case. Which
> lead me to think of exxtreme cases like tm_sec, tm_min, tm_hour,
> tm_mday and tm_mon all at INT_MAX, and tm_year set to a sufficiently
> large negative value.
>
> Am I missing something, or would a conforming implementation have to
> handle this?
I think so. The only out I can imagine is that if mktime()
cannot determine whether Standard or Daylight time prevails, it
may be unable to find "the" corresponding time_t value and could
then return (time_t)-1 to indicate failure. But if the question
boils down to "Must mktime() be careful about overflow in its
internal computations?" I think the answer must be "Yes."
--
Eric Sosman
esosman@comcast-dot-net.invalid
[toc] | [prev] | [next] | [standalone]
| From | Anders Wegge Keller <wegge@wegge.dk> |
|---|---|
| Date | 2012-12-06 17:40 +0100 |
| Message-ID | <87lidb16dx.fsf@huddi.jernurt.dk> |
| In reply to | #28983 |
Eric Sosman <esosman@comcast-dot-net.invalid> writes: > On 12/6/2012 9:25 AM, Anders Wegge Keller wrote: >> According to the C2011 draft I have available, the values in the >> struct tm, passed to mktime(), are not restricted to the normalized >> ranges. (2.27.2.3 §2). > ITYM 7.27.2.3. yes. >> Is this to be taken literally, > That's the usual way to take normative text ... As for legislative works, the wording of normative standards doesn't always mean what the un-initiated takes them to mean. ... > then return (time_t)-1 to indicate failure. But if the question > boils down to "Must mktime() be careful about overflow in its > internal computations?" I think the answer must be "Yes." I guess my question can be reduced to exactly that. -- /Wegge Leder efter redundant peering af dk.*,linux.debian.*
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2012-12-06 14:20 -0500 |
| Message-ID | <k9qr5b$st$1@dont-email.me> |
| In reply to | #28989 |
On 12/6/2012 11:40 AM, Anders Wegge Keller wrote:
> Eric Sosman <esosman@comcast-dot-net.invalid> writes:
>> [...]
>> then return (time_t)-1 to indicate failure. But if the question
>> boils down to "Must mktime() be careful about overflow in its
>> internal computations?" I think the answer must be "Yes."
>
> I guess my question can be reduced to exactly that.
Okay: I'm sticking with "Yes."
FWIW, PJ Plauger seems to agree (he's non-normative, but since
he served on the library subcommittee for the original ANSI Standard,
he's a pretty good indicator of intent). In "The Standard C Library"
he exhibits a sample implementation of mktime(), and in describing
its underpinnings he writes
"You can start with the year 2000, back up 2,000 months,
and advance 2 billion seconds, for example. [...] The
logic is carefully crafted to avoid integer overflow
regardless of argument values."
--
Eric Sosman
esosman@comcast-dot-net.invalid
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2012-12-06 12:28 -0800 |
| Message-ID | <lnfw3iq60r.fsf@nuthaus.mib.org> |
| In reply to | #28991 |
Eric Sosman <esosman@comcast-dot-net.invalid> writes:
> On 12/6/2012 11:40 AM, Anders Wegge Keller wrote:
>> Eric Sosman <esosman@comcast-dot-net.invalid> writes:
>>> [...]
>>> then return (time_t)-1 to indicate failure. But if the question
>>> boils down to "Must mktime() be careful about overflow in its
>>> internal computations?" I think the answer must be "Yes."
>>
>> I guess my question can be reduced to exactly that.
>
> Okay: I'm sticking with "Yes."
>
> FWIW, PJ Plauger seems to agree (he's non-normative, but since
> he served on the library subcommittee for the original ANSI Standard,
> he's a pretty good indicator of intent). In "The Standard C Library"
> he exhibits a sample implementation of mktime(), and in describing
> its underpinnings he writes
>
> "You can start with the year 2000, back up 2,000 months,
> and advance 2 billion seconds, for example. [...] The
> logic is carefully crafted to avoid integer overflow
> regardless of argument values."
You can advance 2 billion seconds *if* int is at least 32 bit (tm_sec is
of type int).
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2012-12-06 17:36 -0500 |
| Message-ID | <k9r6kc$den$1@dont-email.me> |
| In reply to | #28995 |
On 12/6/2012 3:28 PM, Keith Thompson wrote:
> Eric Sosman <esosman@comcast-dot-net.invalid> writes:
>
>> FWIW, PJ Plauger seems to agree (he's non-normative, but since
>> he served on the library subcommittee for the original ANSI Standard,
>> he's a pretty good indicator of intent). In "The Standard C Library"
>> he exhibits a sample implementation of mktime(), and in describing
>> its underpinnings he writes
>>
>> "You can start with the year 2000, back up 2,000 months,
>> and advance 2 billion seconds, for example. [...] The
>> logic is carefully crafted to avoid integer overflow
>> regardless of argument values."
>
> You can advance 2 billion seconds *if* int is at least 32 bit (tm_sec is
> of type int).
Don't complain to me; complain to the quoted author. Besides:
for (int count = 0; count < 100; ++count) {
mktime(tm);
tm->tm_sec += 20000;
}
mktime(tm);
printf("So there, nyaaah!\n");
--
Eric Sosman
esosman@comcast-dot-net.invalid
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2012-12-06 17:42 -0500 |
| Message-ID | <k9r6vb$den$2@dont-email.me> |
| In reply to | #29000 |
On 12/6/2012 5:36 PM, Eric Sosman wrote:
> On 12/6/2012 3:28 PM, Keith Thompson wrote:
>> Eric Sosman <esosman@comcast-dot-net.invalid> writes:
>>
>>> FWIW, PJ Plauger seems to agree (he's non-normative, but since
>>> he served on the library subcommittee for the original ANSI Standard,
>>> he's a pretty good indicator of intent). In "The Standard C Library"
>>> he exhibits a sample implementation of mktime(), and in describing
>>> its underpinnings he writes
>>>
>>> "You can start with the year 2000, back up 2,000 months,
>>> and advance 2 billion seconds, for example. [...] The
>>> logic is carefully crafted to avoid integer overflow
>>> regardless of argument values."
>>
>> You can advance 2 billion seconds *if* int is at least 32 bit (tm_sec is
>> of type int).
>
> Don't complain to me; complain to the quoted author. Besides:
>
> for (int count = 0; count < 100; ++count) {
> mktime(tm);
> tm->tm_sec += 20000;
> }
> mktime(tm);
> printf("So there, nyaaah!\n");
Oh, ratz.
for (int a = 0; a < 1000; ++a) {
for (int b = 0; b < 1000; ++b) {
mktime(tm);
tm->tm_sec += 2000;
}
}
mktime(tm);
printf("So there, this time for sure!\n");
--
Eric Sosman
esosman@comcast-dot-net.invalid
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2012-12-06 12:20 -0800 |
| Message-ID | <lnobi7ortk.fsf@nuthaus.mib.org> |
| In reply to | #28983 |
Eric Sosman <esosman@comcast-dot-net.invalid> writes:
[...]
> Clearly, the intent is to relieve the programmer of the burden
> of all that date arithmetic. If you've got a struct tm representing
> some time T and you want to determine the time at T plus 01:23:45,
> you can blithely add 1*3600+23*60+45 to the tm_sec field and call
> mktime(), and mktime() will figure things out.
[...]
Or you can add 1 to tm_hour, 23 to tm_min, and 45 to tm_sec, and let
mktime() figure *everything* out.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Anders Wegge Keller <wegge@wegge.dk> |
|---|---|
| Date | 2012-12-06 21:37 +0100 |
| Message-ID | <87hany29ze.fsf@huddi.jernurt.dk> |
| In reply to | #28993 |
Keith Thompson <kst-u@mib.org> writes: > Eric Sosman <esosman@comcast-dot-net.invalid> writes: > [...] > > Clearly, the intent is to relieve the programmer of the burden > > of all that date arithmetic. If you've got a struct tm representing > > some time T and you want to determine the time at T plus 01:23:45, > > you can blithely add 1*3600+23*60+45 to the tm_sec field and call > > mktime(), and mktime() will figure things out. > [...] > > Or you can add 1 to tm_hour, 23 to tm_min, and 45 to tm_sec, and let > mktime() figure *everything* out. Yep :) I should have thought about this possibility 10 years ago, and spared myself a lot of trouble. -- /Wegge Leder efter redundant peering af dk.*,linux.debian.*
[toc] | [prev] | [next] | [standalone]
| From | "Heinrich Wolf" <invalid@invalid.invalid> |
|---|---|
| Date | 2012-12-07 09:48 +0100 |
| Message-ID | <k9saf7$jn$1@news.m-online.net> |
| In reply to | #28993 |
"Keith Thompson" <kst-u@mib.org> schrieb im Newsbeitrag news:lnobi7ortk.fsf@nuthaus.mib.org... > Eric Sosman <esosman@comcast-dot-net.invalid> writes: > [...] >> Clearly, the intent is to relieve the programmer of the burden >> of all that date arithmetic. If you've got a struct tm representing >> some time T and you want to determine the time at T plus 01:23:45, >> you can blithely add 1*3600+23*60+45 to the tm_sec field and call >> mktime(), and mktime() will figure things out. > [...] > > Or you can add 1 to tm_hour, 23 to tm_min, and 45 to tm_sec, and let > mktime() figure *everything* out. These may result in different values around a leap second (at the end of some years) or around the transition from normal time to daylight savings time or vice versa.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2012-12-07 08:08 -0500 |
| Message-ID | <k9spov$8cb$2@dont-email.me> |
| In reply to | #29012 |
On 12/07/2012 03:48 AM, Heinrich Wolf wrote: > > "Keith Thompson" <kst-u@mib.org> schrieb im Newsbeitrag > news:lnobi7ortk.fsf@nuthaus.mib.org... >> Eric Sosman <esosman@comcast-dot-net.invalid> writes: >> [...] >>> Clearly, the intent is to relieve the programmer of the burden >>> of all that date arithmetic. If you've got a struct tm representing >>> some time T and you want to determine the time at T plus 01:23:45, >>> you can blithely add 1*3600+23*60+45 to the tm_sec field and call >>> mktime(), and mktime() will figure things out. >> [...] >> >> Or you can add 1 to tm_hour, 23 to tm_min, and 45 to tm_sec, and let >> mktime() figure *everything* out. > > These may result in different values around a leap second (at the end of > some years) or around the transition from normal time to daylight savings > time or vice versa. Yes - and I think the different result you would get in those cases may often be the one that was actually intended. -- James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | "christian.bau" <christian.bau@cbau.wanadoo.co.uk> |
|---|---|
| Date | 2012-12-07 09:23 -0800 |
| Message-ID | <325d43da-95b8-4413-a691-bfaea9a8f68c@f8g2000yqa.googlegroups.com> |
| In reply to | #29016 |
Question: If you start with 28th February 2012, then adding one year, followed by adding two days, will get you 28th Feb 2013, then 2nd Mar 2013. But adding two days, followed by adding one year, will get you 1st Mar 2012, followed by 1st Mar 2013. Not the same. Are there rules for this kind of thing? Is it unspecified or undefined? What's supposed to happen if you add one month to March 31st 2012? The result can't be April 31st; is it April 30th, May 1st, or something else?
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2012-12-07 13:14 -0500 |
| Message-ID | <50C23210.70202@verizon.net> |
| In reply to | #29027 |
On 12/07/2012 12:23 PM, christian.bau wrote:
> Question: If you start with 28th February 2012, then adding one year,
> followed by adding two days, will get you 28th Feb 2013, then 2nd Mar
> 2013. But adding two days, followed by adding one year, will get you
> 1st Mar 2012, followed by 1st Mar 2013. Not the same.
>
> Are there rules for this kind of thing? Is it unspecified or
> undefined?
>
> What's supposed to happen if you add one month to March 31st 2012? The
> result can't be April 31st; is it April 30th, May 1st, or something
> else?
No, the rules for such things aren't specified, and that lack of
specification is a problem.
given:
#include <time.h>
// Two different ways to describe 2012-03-31:
struct tm a = {.tm_year=2012-1900, .tm_month = 3-1, .tm_day = 31};
struct tm b = {.tm_year=2012-1900, .tm_month = 4-1, .tm_day = 0};
a.tm_month += 1;
mktime(&a);
b.tm_month += 1;
mktime(&b);
My preference would be that this point, 'a' represents 2012-05-01, while
'b' represents 2012-04-30. But the standard doesn't address such questions.
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2012-12-07 13:46 -0500 |
| Message-ID | <k9tdhh$aso$1@dont-email.me> |
| In reply to | #29027 |
On 12/7/2012 12:23 PM, christian.bau wrote:
> Question: If you start with 28th February 2012, then adding one year,
> followed by adding two days, will get you 28th Feb 2013, then 2nd Mar
> 2013. But adding two days, followed by adding one year, will get you
> 1st Mar 2012, followed by 1st Mar 2013. Not the same.
mktime() converts dates, which is not the same as doing
arithmetic on them. You may imagine that you are "adding one
year" to 2012-02-28, and you may even use ...tm_year++ to do
it, but when you pass the struct to mktime() it doesn't know
the history of the tm_year value. All it sees is tm_year = 113
(2013 - 1900), and it says "Here I am in 2013; now let's look
at the other fields." If tm_mday is 30, mktime() will make an
adjustment based on the length of 2013's February; it has no
way of knowing that the struct once held a different tm_year.
> Are there rules for this kind of thing? Is it unspecified or
> undefined?
The only rule I see is 7.27.2.2p2: "[...] the final value
of tm_mday is not set until tm_mon and tm_year are determined,"
which I understand as meaning that day-of-month yields to
month and year rather than the other way around.
> What's supposed to happen if you add one month to March 31st 2012? The
> result can't be April 31st; is it April 30th, May 1st, or something
> else?
Again, mktime() can't know what values formerly occupied the
struct fields before the current ones were stored. All it sees
is that tm_mon = 3 (April) and tm_mday = 31; it knows that 31 is
out of range for April and adjusts to May 1.
You could certainly get strange results by doing "the same"
set of adjustments in sequence, with intervening mktime() calls:
struct tm x = ...; // 2012-02-29
x.tm_mon++; // 2012-03-29
mktime(&x); // 2012-03-29
x.tm_mday++; // 2012-03-30
mktime(&x); // 2012-03-30
struct tm y = ...; // 2012-02-29
y.tm_mday++; // 2012-02-30
mktime(&y); // 2012-03-01 corrected
y.tm_mon++; // 2012-04-01
mktime(&y); // 2012-04-01, April Fool!
Each mktime() call has a well-defined outcome, yet the two
sequences lead to different results -- Well, that's just the
way our creaky old calendar crumbles. Still, the creakiness
shouldn't be too terribly surprising to a C programmer, who's
already sensitive to the fact that Order Matters:
int x = 12 / 5 * 3; // 6
int y = 12 * 3 / 5; // 7
If you're comfortable with the fact that doing "the same"
multiplications and divisions in different orders yields
different outcomes, maybe you can reconcile yourself to the
similar situation with date adjustments.
--
Eric Sosman
esosman@comcast-dot-net.invalid
[toc] | [prev] | [next] | [standalone]
| From | "Heinrich Wolf" <invalid@invalid.invalid> |
|---|---|
| Date | 2012-12-07 19:59 +0100 |
| Message-ID | <k9te9e$1in$1@news.m-online.net> |
| In reply to | #29027 |
"christian.bau" <christian.bau@cbau.wanadoo.co.uk> schrieb im Newsbeitrag news:325d43da-95b8-4413-a691-bfaea9a8f68c@f8g2000yqa.googlegroups.com... > Question: If you start with 28th February 2012, then adding one year, > followed by adding two days, will get you 28th Feb 2013, then 2nd Mar > 2013. But adding two days, followed by adding one year, will get you > 1st Mar 2012, followed by 1st Mar 2013. Not the same. > > Are there rules for this kind of thing? Is it unspecified or > undefined? > > What's supposed to happen if you add one month to March 31st 2012? The > result can't be April 31st; is it April 30th, May 1st, or something > else? I tried with my Borland C++Builder 5 on Windows XP. But that is only one of many implementations. 2012-2-28 + 1-0-0 = 2013-2-28 2013-2-28 + 0-0-2 = mktime(2013-2-30) = 2013-3-2 2012-2-28 + 0-0-2 = mktime(2012-2-30) = 2012-3-1 2012-3-1 + 1-0-0 = 2013-3-1 2012-2-28 + 1-0-2 = mktime(2013-2-30) = 2013-3-2 2012-3-31 + 0-1-0 = mktime(2012-4-31) = 2012-5-1
[toc] | [prev] | [next] | [standalone]
| From | Robert Wessel <robertwessel2@yahoo.com> |
|---|---|
| Date | 2012-12-07 15:50 -0600 |
| Message-ID | <evn4c8pbqbkrsqe0nd63n366893vimu0ug@4ax.com> |
| In reply to | #29027 |
On Fri, 7 Dec 2012 09:23:22 -0800 (PST), "christian.bau" <christian.bau@cbau.wanadoo.co.uk> wrote: >Question: If you start with 28th February 2012, then adding one year, >followed by adding two days, will get you 28th Feb 2013, then 2nd Mar >2013. But adding two days, followed by adding one year, will get you >1st Mar 2012, followed by 1st Mar 2013. Not the same. > >Are there rules for this kind of thing? Is it unspecified or >undefined? > >What's supposed to happen if you add one month to March 31st 2012? The >result can't be April 31st; is it April 30th, May 1st, or something >else? The spec for mktime() requires that the year and month are processed first. The real problem is that the questions are not well defined in the real world. One month after January 31st can have a number of different valid answers, depending on the application, and then it may depend on whether or not it's a leap year. And it gets worse. I once worked on an application that needed to produce both the usual monthly/quarterly/annual reports (of course in both calendar and FY forms), but also needed to generate a number of reports on a weekly basis (which matched the marketing/advertising cycle). It seemed that every single customer we had came up with a new combination of rules on how data in weeks the straddled month/quarter/year boundaries were to be counted and numbered (not to mention what counted as the start and end of a week). Sometimes you had separate partial weeks on each side of the boundary, sometime a single week counted on one or the other side of the boundary (sometimes conditionally based on what day of the week the boundary fell on), sometime data was double counted in weeks reported on both sides of the boundary, sometimes you did it one way on one report and a different way on another, sometimes the rules were different for month, quarter and year boundaries... And then there was the question of how they were counted (for example, some customers wanted duplicated weeks to be counted as separate week numbers in the two different periods they fell in, others not, and when you had different schemes trying to keep week numbers consistent was a pain, leading to schemes like reporting a complete week's data as week 31, but the two split parts as 31A and 31B). And at the end of the day, the weekly reports were still difficult to match to the larger periods. But hey, keeps the customers happy.
[toc] | [prev] | [next] | [standalone]
| From | "Heinrich Wolf" <invalid@invalid.invalid> |
|---|---|
| Date | 2012-12-07 21:39 +0100 |
| Message-ID | <k9tk5a$caq$1@news.m-online.net> |
| In reply to | #29012 |
"Heinrich Wolf" <invalid@invalid.invalid> schrieb im Newsbeitrag
news:k9saf7$jn$1@news.m-online.net...
...
> These may result in different values around a leap second (at the end of
> some years) or around the transition from normal time to daylight savings
> time or vice versa.
...
My Fedora 14 man page for mktime tells me that leap seconds exist, but is
there anybody out there who has seen them on a system?
My Fedora 14 man page for mktime in German:
...
Die Elemente der Struktur tm sind:
tm_sec Die Anzahl der Sekunden nach der vollen Minute,
normalerweise im Bereich 0 bis 59, jedoch in Ausnahmefällen bis 61 um
Schaltsekunden zu
erlauben.
...
Translated into English:
...
The elements of struct tm are:
tm_sec The number of seconds after the full minute, normally in the
range 0 to 59, but in exceptional cases up to 61 in order to allow leap
seconds.
...
I searched for leap seconds on 2 different systems: Fedora 14 Linux, and
Windows XP with Borland C++Builder 5.
I expected the calculation localtime(mktime(1970-1-2 00-00-00) + 10000 * 24
* 60 * 60 seconds) to result in a tm struct with some odd seconds, but on
both systems I got 1997-05-20 01-00-00
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2012-12-07 17:17 -0500 |
| Message-ID | <k9tpu9$ptf$1@dont-email.me> |
| In reply to | #29044 |
On 12/7/2012 3:39 PM, Heinrich Wolf wrote:
>
> "Heinrich Wolf" <invalid@invalid.invalid> schrieb im Newsbeitrag
> news:k9saf7$jn$1@news.m-online.net...
> ...
>> These may result in different values around a leap second (at the end
>> of some years) or around the transition from normal time to daylight
>> savings time or vice versa.
> ...
> My Fedora 14 man page for mktime tells me that leap seconds exist, but
> is there anybody out there who has seen them on a system?
>
> My Fedora 14 man page for mktime in German:
> ...
> Die Elemente der Struktur tm sind:
>
> tm_sec Die Anzahl der Sekunden nach der vollen Minute,
> normalerweise im Bereich 0 bis 59, jedoch in Ausnahmefällen bis 61 um
> Schaltsekunden zu
> erlauben.
> ...
> Translated into English:
> ...
> The elements of struct tm are:
>
> tm_sec The number of seconds after the full minute, normally in
> the range 0 to 59, but in exceptional cases up to 61 in order to allow
> leap seconds.
> ...
>
> I searched for leap seconds on 2 different systems: Fedora 14 Linux, and
> Windows XP with Borland C++Builder 5.
> I expected the calculation localtime(mktime(1970-1-2 00-00-00) + 10000 *
> 24 * 60 * 60 seconds) to result in a tm struct with some odd seconds,
> but on both systems I got 1997-05-20 01-00-00
I remember seeing the [0..61] range for tm_sec long ago, and
perhaps it still persists in some non-C documents. Even in the
original 1989 ANSI C Standard, though, the range was [0..60] in
keeping with the fact that leap seconds are added (or removed)
one at a time, never two at once.
As to the calculation -- well, timekeeping is complicated.
POSIX *defines* the day as 86400 seconds, intentionally ignoring
leap seconds (see <http://en.wikipedia.org/wiki/Unix_time>), so
we should not expect a C implementation based on POSIX time to
generate tm_sec==60. The C Standard does not require the library
to overcome this problem:
7.27.1p4: "The range and precision of times representable
in clock_t and time_t are implementation-defined."
7.27.2.4p3: "The time function returns the implementation’s
*best approximation* [emphasis mine] to the current calendar
time."
Timekeeping and time calculation on POSIX and POSIX-like systems
is "close enough for jazz," sufficiently accurate for many purposes
but not astonishingly good. C implementations don't have to do any
better (and on a strictly-conforming POSIX system, I guess they're
actually forbidden to do better).
--
Eric Sosman
esosman@comcast-dot-net.invalid
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2012-12-07 17:50 -0800 |
| Message-ID | <lny5h9nwgn.fsf@nuthaus.mib.org> |
| In reply to | #29048 |
Eric Sosman <esosman@comcast-dot-net.invalid> writes:
> On 12/7/2012 3:39 PM, Heinrich Wolf wrote:
[...]
>> My Fedora 14 man page for mktime in German:
>> ...
>> Die Elemente der Struktur tm sind:
>>
>> tm_sec Die Anzahl der Sekunden nach der vollen Minute,
>> normalerweise im Bereich 0 bis 59, jedoch in Ausnahmefällen bis 61 um
>> Schaltsekunden zu
>> erlauben.
>> ...
>> Translated into English:
>> ...
>> The elements of struct tm are:
>>
>> tm_sec The number of seconds after the full minute, normally in
>> the range 0 to 59, but in exceptional cases up to 61 in order to allow
>> leap seconds.
>> ...
>>
>> I searched for leap seconds on 2 different systems: Fedora 14 Linux, and
>> Windows XP with Borland C++Builder 5.
>> I expected the calculation localtime(mktime(1970-1-2 00-00-00) + 10000 *
>> 24 * 60 * 60 seconds) to result in a tm struct with some odd seconds,
>> but on both systems I got 1997-05-20 01-00-00
>
> I remember seeing the [0..61] range for tm_sec long ago, and
> perhaps it still persists in some non-C documents. Even in the
> original 1989 ANSI C Standard, though, the range was [0..60] in
> keeping with the fact that leap seconds are added (or removed)
> one at a time, never two at once.
The 1990 ISO C standard specifies a range of [0, 61] for tm_sec:
int tm_sec; /* seconds after the minute -- [0, 61] */
with a footnote:
The range [0,61] for tm_sec allows for as many as two leap seconds.
C99 changes the range to [0, 60] and changes the footnote to:
The range [0, 60] for tm_sec allows for a positive leap second.
There's no mention of the change in the C99 rationale.
I've heard (not sure where) that the [0, 61] range in C90 was
the result of a misunderstanding; if it were necessary to have
two leap seconds in a year (which hasn't happened so far) they'd
be added at the end of June and the end of December. I *guess*
that if more than two were required, they'd be spread more or less
evenly through the year.
Are you *sure* that the 1989 ANSI standard specifies [0, 60]?
If so, that would be an inconsistency between ANSI C89 and ISO C90,
and I didn't think there were any.
Interestingly, a 1988 ANSI C draft ("ansi.c.txt", I'm not sure
where I got it) shows a range of [0, 60].
[...]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.c
csiph-web