Compute week number right. Fixes PR 6961, from

Wolfgang Helbig <helbig@Informatik.BA-Stuttgart.DE>
This commit is contained in:
augustss 1999-02-07 17:33:30 +00:00
parent 158083e27d
commit 32482e1058
2 changed files with 104 additions and 27 deletions

View File

@ -34,7 +34,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)strftime.3 5.12 (Berkeley) 6/29/91
.\" $NetBSD: strftime.3,v 1.5 1998/02/11 18:52:25 kleink Exp $
.\" $NetBSD: strftime.3,v 1.6 1999/02/07 17:33:30 augustss Exp $
.\"
.Dd June 29, 1991
.Dt STRFTIME 3
@ -102,6 +102,16 @@ is replaced by the day of the month as a decimal number [01,31].
.It Cm \&%e
is replaced by the day of month as a decimal number [1,31];
single digits are preceded by a blank.
.It Cm \&%G
is replaced by the ISO 8601 year with century as a decimal number.
.TP
.It Cm \&%g
is replaced by the ISO 8601 year without century as a decimal number (00-99).
This is the year that includes the greater part of the week. (Monday as the
first day of a week). See also the
.Ql \&%V
conversion specification.
.TP
.It Cm \&%H
is replaced by the hour (24-hour clock) as a decimal number [00,23].
.It Cm \&%I
@ -149,9 +159,12 @@ is replaced by the weekday (Monday as the first day of the week)
as a decimal number [1,7].
.It Cm \&%V
is replaced by the week number of the year (Monday as the first day of
the week) as a decimal number [01,53]. If the week containing January
1 has four or more days in the new year, then it is week 1; otherwise
it is week 53 of the previous year, and the next week is week 1.
the week) as a decimal number [01,53]. According to ISO 8601 the week
containing January 1 is week 1 if it has four or more days in the new year,
otherwise it is week 53 of the previous year, and the next week is week 1.
The year is given by the
.Ql \&%G
conversion specification.
.It Cm \&%W
is replaced by the week number of the year (Monday as the first day of
the week) as a decimal number [00,53].
@ -188,6 +201,8 @@ The
.Ql \&%C ,
.Ql \&%D ,
.Ql \&%e ,
.Ql \&%g ,
.Ql \&%G ,
.Ql \&%h ,
.Ql \&%k ,
.Ql \&%l ,

View File

@ -1,4 +1,4 @@
/* $NetBSD: strftime.c,v 1.7 1998/12/01 16:07:11 sommerfe Exp $ */
/* $NetBSD: strftime.c,v 1.8 1999/02/07 17:33:30 augustss Exp $ */
/*
* Copyright (c) 1989 The Regents of the University of California.
@ -38,7 +38,7 @@
#if 0
static char *sccsid = "@(#)strftime.c 5.11 (Berkeley) 2/24/91";
#else
__RCSID("$NetBSD: strftime.c,v 1.7 1998/12/01 16:07:11 sommerfe Exp $");
__RCSID("$NetBSD: strftime.c,v 1.8 1999/02/07 17:33:30 augustss Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@ -227,32 +227,94 @@ _fmt(format, t, pt, ptlim)
pt, ptlim))
return (0);
continue;
case 'V':
case 'V': /* ISO 8601 week number */
case 'G': /* ISO 8601 year (four digits) */
case 'g': /* ISO 8601 year (two digits) */
/*
** From Arnold Robbins' strftime version 3.0: "the week number of the
** year (the first Monday as the first day of week 1) as a decimal number
** (01-53)."
** (ado, 1993-05-24)
**
** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
** "Week 01 of a year is per definition the first week which has the
** Thursday in this year, which is equivalent to the week which contains
** the fourth day of January. In other words, the first week of a new year
** is the week which has the majority of its days in the new year. Week 01
** might also contain days from the previous year and the week before week
** 01 of a year is the last week (52 or 53) of the previous year even if
** it contains days from the new year. A week starts with Monday (day 1)
** and ends with Sunday (day 7). For example, the first week of the year
** 1997 lasts from 1996-12-30 to 1997-01-05..."
** (ado, 1996-01-02)
*/
{
/* ISO 8601 Week Of Year:
* If the week (Monday - Sunday) containing
* January 1 has four or more days in the new
* year, then it is week 1; otherwise it is
* week 53 of the previous year and the next
* week is week one.
*/
int year;
int yday;
int wday;
int w;
int week = MON_WEEK(t);
year = t->tm_year + TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
int len;
int bot;
int top;
int days = (((t)->tm_yday + 7 -
((t)->tm_wday ? (t)->tm_wday - 1 : 6)) % 7);
if (days >= 4) {
week++;
} else if (week == 0) {
week = 53;
len = isleap(year) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
/*
** What yday (-3 ... 3) does
** the ISO year begin on?
*/
bot = ((yday + 11 - wday) %
DAYSPERWEEK) - 3;
/*
** What yday does the NEXT
** ISO year begin on?
*/
top = bot -
(len % DAYSPERWEEK);
if (top < -3)
top += DAYSPERWEEK;
top += len;
if (yday >= top) {
++year;
w = 1;
break;
}
if (yday >= bot) {
w = 1 + ((yday - bot) /
DAYSPERWEEK);
break;
}
--year;
yday += isleap(year) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
}
#ifdef XPG4_1994_04_09
if ((w == 52
&& t->tm_mon == TM_JANUARY)
|| (w == 1
&& t->tm_mon == TM_DECEMBER))
w = 53;
#endif /* defined XPG4_1994_04_09 */
if (*format == 'V') {
if (!_conv(w, 2, '0',
pt, ptlim))
return (0);
} else if (*format == 'g') {
if (!_conv(year % 100, 2, '0',
pt, ptlim))
return (0);
} else if (!_conv(year, 4, '0',
pt, ptlim))
return (0);
}
if (!_conv(week, 2, '0', pt, ptlim))
return (0);
continue;
}
case 'W':
if (!_conv(MON_WEEK(t), 2, '0', pt, ptlim))
return (0);