summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--doc/clock.n9
-rw-r--r--generic/tclClock.c49
-rw-r--r--library/clock.tcl69
-rw-r--r--tests/clock.test41
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 <kennykb@acm.org>
+ * 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 <jenglish@users.sourceforge.net>
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