Subject: Re: mktime(3) fails to convert a time in the "spring forward gap"
To: NetBSD Userlevel Technical Discussion List <tech-userlevel@NetBSD.ORG>
From: Bill Studenmund <email@example.com>
Date: 10/09/2002 16:17:37
On Wed, 9 Oct 2002, Greg A. Woods wrote:
> [ On Wednesday, October 9, 2002 at 12:42:43 (-0700), Bill Studenmund wrote: ]
> > I saw the post, and I don't understand mktime well enough to know if it's
> > ok.
> It seems to be OK from the discussions I've read about it.
> Of course that patch is against Eggert's implementation in GNU Libc....
From reading the URL you posted, he seemed to be going along with what
other implementations were doing too, which isn't necessarily right.
> > Here's the scenario. We're in a timezone where we spring forward at 0200,
> > so 02XX doesn't exist.
> > How does this patch deal with the cases of both taking 0130 and adding an
> > hour, and taking 0330 and subtracting an hour? If I understand what it'll
> > do, it will be ok for 0130 + an hour, but get 0330 - an hour wrong.
> But that's not "an hour wrong". That's exactly what ctime(&time(NULL))
> will return in one hour from that 01:30 local time since there is no
> 02:30 for the presumed timezone on the day of the gap.
You mis-parsed that. It wasn't "get 0330" which is an hour wrong, but get
"0330 MINUS one hour" (0130) wrong, since it'll actually give back 0330.
i.e. this works fine for adding times to a struct tm, but not for
> > No, they're broken by design. They are trying to do math on things that
> > don't do math well; timezones have the concept of non-existant times,
> > regardless of whether or not a given timezone has DST or not.
> How can such applications be "broken by design"? They cannot, by
> definition, have any concept of how the DST rules for for any given
> timezone work. All that stuff is necessarily and thankfully hidden from
> view by mktime() et al. Doing math on struct tm fields is very common
> practice in my experience.
They are broken by design because they are trying to do something they
can't do right, as you note.
Sounds like what we need is tmadd(struct tm *atime, struct tm *delta),
where you have a struct tm and you pass in an explicit delta. *atime gets
updated as per delta.
You set all fields in *delta to zero other than the one(s) you want to
change. You set the latter to the amounts you want to adjust. Thus to add
an hour to a date, you set tm_hour = 1. To subtract a month, you instead
set tm_mon = -1.