Bug 4976 - Daylight saving time calculation fails when M-specifier is larger than number of weeks in the month
Summary: Daylight saving time calculation fails when M-specifier is larger than number...
Status: RESOLVED FIXED
Alias: None
Product: uClibc
Classification: Unclassified
Component: Other (show other bugs)
Version: 0.9.30.1
Hardware: Other Linux
: P5 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-03-25 08:29 UTC by Petteri Aimonen
Modified: 2012-03-30 15:58 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Petteri Aimonen 2012-03-25 08:29:52 UTC
Today, 2012-03-25, uClibc did not switch to DST even though glibc-based systems using the same TZ string did.

root@busybox:~# TZ='EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00' date
Sun Mar 25 10:15:39 EET 2012

root@debian:~# TZ='EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00' date
Sun Mar 25 11:20:01 EEST 2012

--

I think the problem is related to the parsing of the M3.5.0 specifier, which means "last Sunday of March". That meaning of '5' is documented atleast here:
http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html and it is necessary to properly specify the DST observed in eastern Europe.

The bug is probably somewhere around here. Lines 700-702 seem to implement the functionality, but for some reason it is not working.
http://git.uclibc.org/uClibc/tree/libc/misc/time/time.c#n685

--

Because the commands given in the beginning will stop working when time proceeds, use this command for testing:
TZ='EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00' date -d '2012-03-25 12:00' +%Z

When working correctly, it should print 'EEST' (Eastern European Summer Time). Busybox currently prints EET.
Comment 1 A.Mazur 2012-03-29 21:54:55 UTC
I observe the same issue with uclibc 0.9.30.1.
It seems that due to some bug it expects that in March 2012 there will be at least an extra sunday (32th?)

# TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-03-30 12:00'
Fri Mar 30 12:00:00 CET 2012
# TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-03-31 12:00'
Sat Mar 31 12:00:00 CET 2012
# TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-03-32 12:00'
Sun Apr  1 12:00:00 CEST 2012
# TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-04-01 12:00'
Sun Apr  1 12:00:00 CEST 2012

CEST begins on last sunday of March. There were 4 sundays in March, the last was on the 25th.

I didn't find any timezone-related fixes in the change logs since 0.9.30.1.
Comment 2 Bernhard Reutner-Fischer 2012-03-30 15:55:43 UTC
(In reply to comment #0)
> Today, 2012-03-25, uClibc did not switch to DST even though glibc-based systems
> using the same TZ string did.
> 
> root@busybox:~# TZ='EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00' date
> Sun Mar 25 10:15:39 EET 2012
> 
> root@debian:~# TZ='EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00' date
> Sun Mar 25 11:20:01 EEST 2012

This was fixed in 0.9.33:

$ TZ='EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00' ./busybox \
-d '2012-03-25 12:00' +%Z
EEST
Comment 3 Bernhard Reutner-Fischer 2012-03-30 15:58:05 UTC
(In reply to comment #1)
> I observe the same issue with uclibc 0.9.30.1.
> It seems that due to some bug it expects that in March 2012 there will be at
> least an extra sunday (32th?)
> 
> # TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-03-30 12:00'
> Fri Mar 30 12:00:00 CET 2012
> # TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-03-31 12:00'
> Sat Mar 31 12:00:00 CET 2012
> # TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-03-32 12:00'
> Sun Apr  1 12:00:00 CEST 2012
> # TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 date -d '2012-04-01 12:00'
> Sun Apr  1 12:00:00 CEST 2012
> 
> CEST begins on last sunday of March. There were 4 sundays in March, the last
> was on the 25th.
> 
> I didn't find any timezone-related fixes in the change logs since 0.9.30.1.

This was fixed in 0.9.33:

$ TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 ./date_uClibc '2012-03-30 12:00' '2012-03-31 12:00' '2012-03-32 12:00' '2012-04-01 12:00' 
Using TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3
'2012-03-30 12:00' -> '2012-03-30 12:00'
'2012-03-31 12:00' -> '2012-03-31 12:00'
'2012-03-32 12:00' -> '1900-01-?? 00:00' got INVALID date
'2012-04-01 12:00' -> '2012-04-01 12:00'
$ TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 ./date_glibc '2012-03-30 12:00' '2012-03-31 12:00' '2012-03-32 12:00' '2012-04-01 12:00' 
Using TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3
'2012-03-30 12:00' -> '2012-03-30 12:00'
'2012-03-31 12:00' -> '2012-03-31 12:00'
'2012-03-32 12:00' -> '2012-03-00 00:00' got INVALID date
'2012-04-01 12:00' -> '2012-04-01 12:00'
$ cat date.c
/*
TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3 ./date '2012-03-31 12:00' '2012-03-32 12:00'
*/
#define _XOPEN_SOURCE
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv) {
	struct tm tm;
	char buf[128];
	const char * date_fmt = "%Y-%m-%d %H:%M";
	char *chp;
	int ret = 0;

	if ((chp = getenv("TZ")) == NULL)
		return 2;
	printf("Using TZ=%s\n", chp);
	while (++argv && *argv) {
		memset(&tm, 0, sizeof(struct tm));
		memset(&buf, 0, sizeof buf);

		chp = strptime(*argv, date_fmt, &tm);
		ret |= chp == NULL; /* invalid date */
		strftime(buf, sizeof buf, date_fmt, &tm);
		printf("'%s' -> '%s'%s\n", *argv, buf,
				chp == NULL ? " got INVALID date" : "");
	}
	return ret;
}