diff options
author | Kevin B Kenny <kennykb@acm.org> | 2004-05-18 21:52:56 (GMT) |
---|---|---|
committer | Kevin B Kenny <kennykb@acm.org> | 2004-05-18 21:52:56 (GMT) |
commit | 9952f1458ffdf3f22b1013dab019fb273dff357f (patch) | |
tree | 68fc172017b9d4cf65f0d772cfaada0f085f643c /compat | |
parent | 796e34e6aaf5f3b99f1c0e9d7906567eeb2ad087 (diff) | |
download | tcl-9952f1458ffdf3f22b1013dab019fb273dff357f.zip tcl-9952f1458ffdf3f22b1013dab019fb273dff357f.tar.gz tcl-9952f1458ffdf3f22b1013dab019fb273dff357f.tar.bz2 |
* compat/strftime.c (_fmt, ISO8601Week):
* doc/clock.n:
* tests/clock.test: Major rework to the handling of ISO8601
week numbers. Now passes all the %G and %V test cases on
Windows, Linux and Solaris [Bugs #500285, #500389, and #852944]
Diffstat (limited to 'compat')
-rw-r--r-- | compat/strftime.c | 98 |
1 files changed, 77 insertions, 21 deletions
diff --git a/compat/strftime.c b/compat/strftime.c index 027e373..dbd7d54 100644 --- a/compat/strftime.c +++ b/compat/strftime.c @@ -10,7 +10,7 @@ * * Changes 2002 Copyright (c) 2002 ActiveState Corporation. * - * RCS: @(#) $Id: strftime.c,v 1.10 2002/05/29 00:19:39 hobbs Exp $ + * RCS: @(#) $Id: strftime.c,v 1.10.2.1 2004/05/18 21:52:56 kennykb Exp $ */ /* @@ -47,7 +47,7 @@ */ #if defined(LIBC_SCCS) -static char *rcsid = "$Id: strftime.c,v 1.10 2002/05/29 00:19:39 hobbs Exp $"; +static char *rcsid = "$Id: strftime.c,v 1.10.2.1 2004/05/18 21:52:56 kennykb Exp $"; #endif /* LIBC_SCCS */ #include <time.h> @@ -113,6 +113,7 @@ static int _conv _ANSI_ARGS_((int n, int digits, int pad)); static int _secs _ANSI_ARGS_((const struct tm *t)); static size_t _fmt _ANSI_ARGS_((const char *format, const struct tm *t)); +static int ISO8601Week _ANSI_ARGS_((CONST struct tm* t, int *year )); size_t TclpStrftime(s, maxsize, format, t, useGMT) @@ -229,6 +230,24 @@ _fmt(format, t) if (!_conv(t->tm_mday, 2, ' ')) return(0); continue; + case 'g': + { + int year; + ISO8601Week( t, &year ); + if ( !_conv( year%100, 2, '0' ) ) { + return( 0 ); + } + continue; + } + case 'G': + { + int year; + ISO8601Week( t, &year ); + if ( !_conv( year, 4, '0' ) ) { + return( 0 ); + } + continue; + } case 'H': if (!_conv(t->tm_hour, 2, '0')) return(0); @@ -301,25 +320,7 @@ _fmt(format, t) continue; case 'V': { - /* 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 week = MON_WEEK(t); - - 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; - } - + int week = ISO8601Week( t, NULL ); if (!_conv(week, 2, '0')) return(0); continue; @@ -449,3 +450,58 @@ _add(str) return(1); } } + +static int +ISO8601Week( t, year ) + CONST struct tm* t; + int* year; +{ + /* Find the day-of-year of the Thursday in + * the week in question. */ + + int ydayThursday; + int week; + if ( t->tm_wday == 0 ) { + ydayThursday = t->tm_yday - 3; + } else { + ydayThursday = t->tm_yday - t->tm_wday + 4; + } + + if ( ydayThursday < 0 ) { + + /* This is the last week of the previous year. */ + if ( IsLeapYear(( t->tm_year + TM_YEAR_BASE - 1 )) ) { + ydayThursday += 366; + } else { + ydayThursday += 365; + } + week = ydayThursday / 7 + 1; + if ( year != NULL ) { + *year = t->tm_year + 1899; + } + + } else if ( ( IsLeapYear(( t -> tm_year + TM_YEAR_BASE )) + && ydayThursday >= 366 ) + || ( !IsLeapYear(( t -> tm_year + + TM_YEAR_BASE )) + && ydayThursday >= 365 ) ) { + + /* This is week 1 of the following year */ + + week = 1; + if ( year != NULL ) { + *year = t->tm_year + 1901; + } + + } else { + + week = ydayThursday / 7 + 1; + if ( year != NULL ) { + *year = t->tm_year + 1900; + } + + } + + return week; + +} |