time.c and TZ in uClibc

slyda at verizon.net slyda at verizon.net
Tue Oct 11 16:28:53 UTC 2011


   Hello,
   I am using uClibc on an embedded linux target, and we are using uClibc
   standard time functions to automatically adjust for daylight savings
   time on our device.  For the most part, this has worked flawlessly for
   over a year.
   It appears now that the adjustment for Central European time (CET) for
   March of 2012 is not computing right.
   The timezone variable, TZ, which is understood by uClibc is set to:
   CET-1CEST,M3.5.0,M10.5.0/3
   Which, if I understand the format correctly...means that the CET->CEST
   transition should happen at 02:00 on the last Sunday in March (March
   25, 2012).   However, in 2012, we are seeing this transition happen in
   the first Sunday in April (April 1, 2012) at 02:00, one week late.  We
   observe this problem with busybox's "date" utility, which simply uses
   the uclibc localtime.
   After looking at the source in libc/misc/time/time.c, we believe there
   might be an issue in the tm_isdst() function in this file.  If you use
   the last weekend in march,2012 as the input value for this function, it
   gives you an offset to April 1, 2012, not March 25, 2012.
   The code in question seems to be this:
   <snip>
monlen = 31 + day_cor[r->month -1] - day_cor[r->month];
if (isleap && (r->month > 1))
    ++monlen;
}

   </snip>
   In this case r->month is 3, so this evaluates to:
   monlen = 31 + 34 - 34
   Which is 31 days in March, which is correct.  However the next line
   causes monlen to be incremented to 32 (because 2012 is a leap year, and
   r->month is greater than 1).
   With monlen set to 32..the following code gets executed:
/* Wweekday (0 is Sunday) of 1st of the month
 * is (day0 + day) % 7. */
if ((mday = r->day - ((day0 + day) % 7)) >= 0) {
    mday -= 7; /* Back up into prev month since r->week>0. */
}
if ((mday += 7 * r->week) >= monlen) {
    mday -= 7;
}
In this example, day0 is the day of the week offset of the first day of the year
, which in 2012 is 0 for Sunday. "day" is the 0th day offset from January first
for the first day of the month, which for March 1, 2012 is 60.  The (day0 +
day) % 7 calculation gives a value of 4.  r->day is 0 (For Sunday), so after the
 first 'if' statement, mday will be -4.
In the second 'if' statement above r->week is 5. This causes mday to be evaluate
d to 7 * 5 + -4 = 31. 31 is less than the calculated monlen of 32, so the "mday
-= 7" code is not executed.
At the end of this code section, the 'day' count is added to 'mday' to give the
DST day, which comes out to April 1, 2012...where it should be March 25, 2012.
I'm using version 0.9.29 of uClibc, but the same code appears in the latest vers
ion as well.   I'm wondering if anyone else has encountered this issue and could
 offer some guidance on this code.
Thanks in advance for your help,
-Steve


More information about the uClibc mailing list