From 3da9c09d810510b812376df89e54ef578a4571d4 Mon Sep 17 00:00:00 2001 From: Kevin B Kenny Date: Mon, 31 Jul 2006 03:27:12 +0000 Subject: Bug 1426279 --- ChangeLog | 13 +++++++--- doc/clock.n | 9 +++++++ generic/tclClock.c | 49 ++++++++++++++++++++++++++++---------- library/clock.tcl | 69 +++++++++++++++++++++++++++++++++++++++++++----------- tests/clock.test | 41 +++++++++++++++++++++++++++++++- 5 files changed, 151 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index 05e03ef..b32a62a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,21 @@ 2006-07-30 Kevin Kenny + * generic/tclClock.c (GetJulianDayFromEraYearMonthDay): + Corrected several errors in converting dates before the + Common Era. [Bug 1426279] * library/clock.tcl: Corrected syntax errors in generated code for %EC, %Ey, and %W format groups [Bug 1505383]. Corrected a bug in cache management for format strings containing [glob] - metacharacters [Bug 1494664]. + metacharacters [Bug 1494664]. Corrected several errors in + formatting/scanning of years prior to the Common Era, and + added the missing %EE format group to indicate the era. * tools/makeTestCases.tcl: Added code to make sure that %U and %V format groups are included in the tests. (The code depends on %U and %V formatting working correctly when 'makeTestCases.tcl' - is run, rather than making a completely independent check.) - * tests/clock.test: Rebuilt with new test cases. + is run, rather than making a completely independent check.) Added + tests for [glob] metacharacters in strings. Added tests for + years prior to the Common Era. + * tests/clock.test: Rebuilt with new test cases for all the above. 2006-07-30 Joe English diff --git a/doc/clock.n b/doc/clock.n index 7bcfbb9..d4d09e8 100644 --- a/doc/clock.n +++ b/doc/clock.n @@ -493,6 +493,15 @@ On output, produces a locale-dependent name of an era in the locale's alternative calendar. On input, matches the name of the era or any unique prefix. .TP +\fB%EE\fR +On output, produces the string \fBB.C.E.\fR or \fBC.E.\fR, or a +string of the same meaning in the locale, to indicate whether \fB%Y\fR refers +to years before or after Year 1 of the Common Era. On input, accepts +the string \fBB.C.E.\fR, \fBB.C.\fR, \fBC.E.\fR, \fBA.D.\fR, or the +abbreviation appropriate to the current locale, and uses it to fix +whether \fB%Y\fR refers to years before or after Year 1 of the +Common Era. +.TP \fB%Ex\fR On output, produces a locale-dependent representation of the date in the locale's alternative calendar. On input, matches diff --git a/generic/tclClock.c b/generic/tclClock.c index 6a334ad..655dedc 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclClock.c,v 1.51 2006/02/01 23:34:38 dkf Exp $ + * RCS: @(#) $Id: tclClock.c,v 1.52 2006/07/31 03:27:12 kennykb Exp $ */ #include "tclInt.h" @@ -370,7 +370,7 @@ ClockConvertlocaltoutcObjCmd( * tzOffset - Time zone offset in seconds east of Greenwich * tzName - Time zone name * julianDay - Julian Day Number in the local time zone - * +v * *---------------------------------------------------------------------- */ @@ -799,6 +799,11 @@ ConvertLocalToUTCUsingC( fields->julianDay = (int) ((fields->localSeconds + JULIAN_SEC_POSIX_EPOCH) / SECONDS_PER_DAY); + secondOfDay = (int)(fields->localSeconds % SECONDS_PER_DAY); + if (secondOfDay < 0) { + secondOfDay += SECONDS_PER_DAY; + --fields->julianDay; + } GetGregorianEraYearDay(fields, changeover); GetMonthDay(fields); @@ -809,10 +814,6 @@ ConvertLocalToUTCUsingC( timeVal.tm_year = fields->year - 1900; timeVal.tm_mon = fields->month - 1; timeVal.tm_mday = fields->dayOfMonth; - secondOfDay = (int)(fields->localSeconds % SECONDS_PER_DAY); - if (secondOfDay < 0) { - secondOfDay += SECONDS_PER_DAY; - } timeVal.tm_hour = (secondOfDay / 3600) % 24; timeVal.tm_min = (secondOfDay / 60) % 60; timeVal.tm_sec = secondOfDay % 60; @@ -1213,6 +1214,10 @@ GetGregorianEraYearDay( day = jday - JDAY_1_JAN_1_CE_GREGORIAN; n = day / FOUR_CENTURIES; day %= FOUR_CENTURIES; + if (day < 0) { + day += FOUR_CENTURIES; + --n; + } year += 400 * n; /* @@ -1248,7 +1253,11 @@ GetGregorianEraYearDay( */ n = day / FOUR_YEARS; - day %= 1461; + day %= FOUR_YEARS; + if (day < 0) { + day += FOUR_YEARS; + --n; + } year += 4 * n; /* @@ -1271,7 +1280,7 @@ GetGregorianEraYearDay( * store era/year/day back into fields. */ - if (year < 0) { + if (year <= 0) { fields->era = BCE; fields->year = 1 - year; } else { @@ -1388,6 +1397,7 @@ GetJulianDayFromEraYearMonthDay( int year; int ym1; int month; int mm1; int q; int r; + int ym1o4; int ym1o100; int ym1o400; if (fields->era == BCE) { year = 1 - fields->year; @@ -1428,13 +1438,25 @@ GetJulianDayFromEraYearMonthDay( * Try an initial conversion in the Gregorian calendar. */ + ym1o4 = ym1 / 4; + if (ym1 % 4 < 0) { + --ym1o4; + } + ym1o100 = ym1 / 100; + if (ym1 % 100 < 0) { + --ym1o100; + } + ym1o400 = ym1 / 400; + if (ym1 % 400 < 0) { + --ym1o400; + } fields->julianDay = JDAY_1_JAN_1_CE_GREGORIAN - 1 + fields->dayOfMonth + daysInPriorMonths[IsGregorianLeapYear(fields)][month - 1] + (ONE_YEAR * ym1) - + (ym1 / 4) - - (ym1 / 100) - + (ym1 / 400); + + ym1o4 + - ym1o100 + + ym1o400; /* * If the resulting date is before the Gregorian changeover, convert in @@ -1447,7 +1469,7 @@ GetJulianDayFromEraYearMonthDay( + fields->dayOfMonth + daysInPriorMonths[year%4 == 0][month - 1] + (365 * ym1) - + (ym1 / 4); + + ym1o4; } } @@ -1509,6 +1531,9 @@ WeekdayOnOrBefore( int julianDay /* Reference date */ ) { int k = (dayOfWeek + 6) % 7; + if (k < 0) { + k += 7; + } return julianDay - ((julianDay - k) % 7); } diff --git a/library/clock.tcl b/library/clock.tcl index 4a10ad3..d6ef8a3 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -13,7 +13,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: clock.tcl,v 1.32 2006/07/30 19:15:41 kennykb Exp $ +# RCS: @(#) $Id: clock.tcl,v 1.33 2006/07/31 03:27:13 kennykb Exp $ # #---------------------------------------------------------------------- @@ -395,21 +395,34 @@ proc ::tcl::clock::Initialize {} { { julianDay } 1 {} - { century yearOfCentury month dayOfMonth } 2 { + { era century yearOfCentury month dayOfMonth } 2 { + dict set date year [expr { 100 * [dict get $date century] + + [dict get $date yearOfCentury] }] + set date [GetJulianDayFromEraYearMonthDay $date[set date {}] \ + $changeover] + } + { era century yearOfCentury dayOfYear } 2 { + dict set date year [expr { 100 * [dict get $date century] + + [dict get $date yearOfCentury] }] + set date [GetJulianDayFromEraYearDay $date[set date {}] \ + $changeover] + } + + { century yearOfCentury month dayOfMonth } 3 { dict set date era CE dict set date year [expr { 100 * [dict get $date century] + [dict get $date yearOfCentury] }] set date [GetJulianDayFromEraYearMonthDay $date[set date {}] \ $changeover] } - { century yearOfCentury dayOfYear } 2 { + { century yearOfCentury dayOfYear } 3 { dict set date era CE dict set date year [expr { 100 * [dict get $date century] + [dict get $date yearOfCentury] }] set date [GetJulianDayFromEraYearDay $date[set date {}] \ $changeover] } - { iso8601Century iso8601YearOfCentury iso8601Week dayOfWeek } 2 { + { iso8601Century iso8601YearOfCentury iso8601Week dayOfWeek } 3 { dict set date era CE dict set date iso8601Year \ [expr { 100 * [dict get $date iso8601Century] @@ -418,19 +431,19 @@ proc ::tcl::clock::Initialize {} { $changeover] } - { yearOfCentury month dayOfMonth } 3 { + { yearOfCentury month dayOfMonth } 4 { set date [InterpretTwoDigitYear $date[set date {}] $baseTime] dict set date era CE set date [GetJulianDayFromEraYearMonthDay $date[set date {}] \ $changeover] } - { yearOfCentury dayOfYear } 3 { + { yearOfCentury dayOfYear } 4 { set date [InterpretTwoDigitYear $date[set date {}] $baseTime] dict set date era CE set date [GetJulianDayFromEraYearDay $date[set date {}] \ $changeover] } - { iso8601YearOfCentury iso8601Week dayOfWeek } 3 { + { iso8601YearOfCentury iso8601Week dayOfWeek } 4 { set date [InterpretTwoDigitYear \ $date[set date {}] $baseTime \ iso8601YearOfCentury iso8601Year] @@ -439,40 +452,40 @@ proc ::tcl::clock::Initialize {} { $changeover] } - { month dayOfMonth } 4 { + { month dayOfMonth } 5 { set date [AssignBaseYear $date[set date {}] \ $baseTime $timeZone $changeover] set date [GetJulianDayFromEraYearMonthDay $date[set date {}] \ $changeover] } - { dayOfYear } 4 { + { dayOfYear } 5 { set date [AssignBaseYear $date[set date {}] \ $baseTime $timeZone $changeover] set date [GetJulianDayFromEraYearDay $date[set date {}] \ $changeover] } - { iso8601Week dayOfWeek } 4 { + { iso8601Week dayOfWeek } 5 { set date [AssignBaseIso8601Year $date[set date {}] \ $baseTime $timeZone $changeover] set date [GetJulianDayFromEraYearWeekDay $date[set date {}] \ $changeover] } - { dayOfMonth } 5 { + { dayOfMonth } 6 { set date [AssignBaseMonth $date[set date {}] \ $baseTime $timeZone $changeover] set date [GetJulianDayFromEraYearMonthDay $date[set date {}] \ $changeover] } - { dayOfWeek } 6 { + { dayOfWeek } 7 { set date [AssignBaseWeek $date[set date {}] \ $baseTime $timeZone $changeover] set date [GetJulianDayFromEraYearWeekDay $date[set date {}] \ $changeover] } - {} 7 { + {} 8 { set date [AssignBaseJulianDay $date[set date {}] \ $baseTime $timeZone $changeover] } @@ -1093,6 +1106,15 @@ proc ::tcl::clock::ParseClockFormatFormat2 {format locale procName} { percentE { # Character following %E set state {} switch -exact -- $char { + E { + append formatString %s + append substituents { } \ + [string map \ + [list @BCE@ [list [mc BCE]] \ + @CE@ [list [mc CE]]] \ + {[dict get {BCE @BCE@ CE @CE@} \ + [dict get $date era]]}] + } C { # Locale-dependent era append formatString %s append substituents { [dict get $date localeEra]} @@ -1875,6 +1897,22 @@ proc ::tcl::clock::ParseClockScanFormat {formatString locale} { append re (?: $regex ) } + E { + set l {} + dict set l [mc BCE] BCE + dict set l [mc CE] CE + dict set l B.C.E. BCE + dict set l C.E. CE + dict set l B.C. BCE + dict set l A.D. CE + foreach {regex lookup} [UniquePrefixRegexp $l] break + append re ( $regex ) + dict set fieldSet era [incr fieldCount] + append postcode "dict set date era \["\ + "dict get " [list $lookup] " \$field" \ + [incr captureCount] \ + "\]\n" + } y { # Locale-dependent year of the era foreach {regex lookup} \ [LocaleNumeralMatcher $locale] break @@ -4007,7 +4045,7 @@ proc ::tcl::clock::DeterminePosixDSTTime { z bound y } { proc ::tcl::clock::GetLocaleEra { date etable } { set index [BSearch $etable [dict get $date localSeconds]] - if { $index < 0 } { + if { $index < 0} { dict set date localeEra \ [::format %02d [expr { [dict get $date year] / 100 }]] dict set date localeYear \ @@ -4225,6 +4263,9 @@ proc ::tcl::clock::WeekdayOnOrBefore { weekday j } { proc ::tcl::clock::BSearch { list key } { + if {[llength $list] == 0} { + return -1 + } if { $key < [lindex $list 0 0] } { return -1 } diff --git a/tests/clock.test b/tests/clock.test index 5b549a4..97b385c 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -11,7 +11,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: clock.test,v 1.65 2006/07/30 19:15:42 kennykb Exp $ +# RCS: @(#) $Id: clock.test,v 1.66 2006/07/31 03:27:13 kennykb Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 @@ -216,6 +216,8 @@ namespace eval ::tcl::clock { LOCALE_DATE_FORMAT {die %Od mensis %Om annoque %EY} LOCALE_TIME_FORMAT {%OH h %OM m %OS s} LOCALE_DATE_TIME_FORMAT {%Ex %EX} + BCE {Before Christ} + CE {Anno Domini} } } @@ -36042,6 +36044,43 @@ test clock-54.2 {glob specials in [clock scan]} \ } \ -result 0 +test clock-55.1 {Common Era} { + clock format -62135769600 -gmt 1 -format {%d %m %Y %EE} +} {01 01 0001 C.E.} +test clock-55.2 {Common Era} { + clock format -62135769600 -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} {01 01 0001 Anno Domini} +test clock-55.3 {Before the Common Era} { + clock format -62135769601 -gmt 1 -format {%d %m %Y %EE} +} {31 12 0001 B.C.E.} +test clock-55.4 {Before the Common Era} { + clock format -62135769601 -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} {31 12 0001 Before Christ} +test clock-55.5 {Common Era} { + clock scan {01 01 0001 C.E.} \ + -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} -62135769600 +test clock-55.6 {Common Era} { + clock scan {01 01 0001 A.D.} \ + -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} -62135769600 +test clock-55.7 {Common Era} { + clock scan {01 01 0001 Anno Domini} \ + -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} -62135769600 +test clock-55.8 {Before the Common Era} { + clock scan {31 12 0001 B.C.E.} \ + -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} -62135856000 +test clock-55.9 {Common Era} { + clock scan {31 12 0001 B.C.} \ + -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} -62135856000 +test clock-55.10 {Common Era} { + clock scan {31 12 0001 Before Christ} \ + -gmt 1 -format {%d %m %Y %EE} -locale en_US_roman +} -62135856000 + # cleanup namespace delete ::testClock -- cgit v0.12