From f70ebac8b8c9c01999150364b4155b0d50911cbc Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 10 Jan 2017 22:02:10 +0000 Subject: [temp-commit]: ClockFreeScan ready, test case passed (2 failure because of wrong :localtime zone by TZ-switch, to be fixed) --- generic/tclClock.c | 26 +++++-- library/clock.tcl | 198 ++--------------------------------------------------- library/init.tcl | 2 +- tests/clock.test | 12 +++- 4 files changed, 37 insertions(+), 201 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 5710d6d..7256320 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -122,6 +122,7 @@ typedef struct ClockClientData { Tcl_Obj *GMTSetupTZData; Tcl_Obj *LastSetupTimeZone; Tcl_Obj *LastSetupTZData; + Tcl_Obj *LastUsedSetupTimeZone; } ClockClientData; /* @@ -324,6 +325,7 @@ TclClockInit( data->GMTSetupTZData = NULL; data->LastSetupTimeZone = NULL; data->LastSetupTZData = NULL; + data->LastUsedSetupTimeZone = NULL; /* * Install the commands. @@ -477,6 +479,7 @@ ClockConfigureObjCmd( if (i+1 < objc) { timezoneObj = NormTimezoneObj(dataPtr, objv[i+1]); if (optionIndex == CLOCK_SETUP_TZ) { + dataPtr->LastUsedSetupTimeZone = timezoneObj; if (timezoneObj == litPtr[LIT_GMT]) { optionIndex = CLOCK_SETUP_GMT; } else if (timezoneObj == dataPtr->LastSystemTimeZone) { @@ -510,14 +513,15 @@ ClockConfigureObjCmd( if (i+1 < objc) { Tcl_IncrRefCount( dataPtr->LastSetupTimeZone = timezoneObj); - } else if (dataPtr->LastSetupTimeZone) { - Tcl_SetObjResult(interp, dataPtr->LastSetupTimeZone); + } else if (dataPtr->LastUsedSetupTimeZone) { + Tcl_SetObjResult(interp, dataPtr->LastUsedSetupTimeZone); } } } } if (optionIndex == CLOCK_CLEAR_CACHE) { dataPtr->LastTZEpoch = 0; + dataPtr->LastUsedSetupTimeZone = NULL; } } @@ -605,6 +609,11 @@ ClockSetupTimeZone( Tcl_Obj **literals = dataPtr->literals; Tcl_Obj *callargs[2]; + /* if cached (if already setup this one) */ + if (timezoneObj == dataPtr->LastUsedSetupTimeZone) { + return timezoneObj; + } + /* differentiate GMT and system zones, because used often and already set */ timezoneObj = NormTimezoneObj(dataPtr, timezoneObj); if ( timezoneObj == dataPtr->GMTSetupTimeZone @@ -2546,6 +2555,15 @@ ClockScanObjCmd( } */ + if (1) { + /* TODO: Tcled Scan proc - */ + Tcl_Obj *callargs[10]; + memcpy(callargs, objv, objc * sizeof(*objv)); + callargs[0] = Tcl_NewStringObj("::tcl::clock::__org_scan", -1); + return Tcl_EvalObjv(interp, objc, callargs, 0); + } + // Tcl_SetObjResult(interp, Tcl_NewWideIntObj(10000000)); + return TCL_OK; } @@ -2635,10 +2653,10 @@ ClockFreeScan( if (yy.dateHaveDate) { if (yy.dateYear < 100) { - yy.dateYear += ClockCurrentYearCentury(clientData, interp); - if (yy.dateYear > ClockGetYearOfCenturySwitch(clientData, interp)) { + if (yy.dateYear >= ClockGetYearOfCenturySwitch(clientData, interp)) { yy.dateYear -= 100; } + yy.dateYear += ClockCurrentYearCentury(clientData, interp); } date.era = CE; date.year = yy.dateYear; diff --git a/library/clock.tcl b/library/clock.tcl index 90b3c69..b4a7639 100755 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -289,7 +289,7 @@ proc ::tcl::clock::Initialize {} { # Current year century and year of century switch variable CurrentYearCentury 2000 - variable YearOfCenturySwitch 37 + variable YearOfCenturySwitch 38 # Translation table to map Windows TZI onto cities, so that the Olson # rules can apply. In some cases the mapping is ambiguous, so it's wise @@ -1249,18 +1249,6 @@ proc ::tcl::clock::__org_scan { args } { set timezone :GMT } - if { ![info exists saw(-format)] } { - # Perhaps someday we'll localize the legacy code. Right now, it's not - # localized. - if { [info exists saw(-locale)] } { - return -code error \ - -errorcode [list CLOCK flagWithLegacyFormat] \ - "legacy \[clock scan\] does not support -locale" - - } - return [FreeScan $string $base $timezone $locale] - } - # Change locale if a fresh locale has been given on the command line. EnterLocale $locale @@ -1279,184 +1267,6 @@ proc ::tcl::clock::__org_scan { args } { #---------------------------------------------------------------------- # -# FreeScan -- -# -# Scans a time in free format -# -# Parameters: -# string - String containing the time to scan -# base - Base time, expressed in seconds from the Epoch -# timezone - Default time zone in which the time will be expressed -# locale - (Unused) Name of the locale where the time will be scanned. -# -# Results: -# Returns the date and time extracted from the string in seconds from -# the epoch -# -#---------------------------------------------------------------------- - -proc ::tcl::clock::__org_FreeScan { string base timezone locale } { - - variable TZData - - # Get the data for time changes in the given zone - if {$timezone eq {}} { - set timezone [GetSystemTimeZone] - } - try { - SetupTimeZone $timezone - } on error {retval opts} { - dict unset opts -errorinfo - return -options $opts $retval - } - - # Extract year, month and day from the base time for the parser to use as - # defaults - - set date [GetDateFields $base $TZData($timezone) 2361222] - dict set date secondOfDay [expr { - [dict get $date localSeconds] % 86400 - }] - - # Parse the date. The parser will return a list comprising date, time, - # time zone, relative month/day/seconds, relative weekday, ordinal month. - - try { - set scanned [Oldscan $string \ - [dict get $date year] \ - [dict get $date month] \ - [dict get $date dayOfMonth]] - lassign $scanned \ - parseDate parseTime parseZone parseRel \ - parseWeekday parseOrdinalMonth - } on error message { - return -code error \ - "unable to convert date-time string \"$string\": $message" - } - - # If the caller supplied a date in the string, update the 'date' dict with - # the value. If the caller didn't specify a time with the date, default to - # midnight. - - if { [llength $parseDate] > 0 } { - lassign $parseDate y m d - if { $y < 100 } { - variable YearOfCenturySwitch - if { $y > $YearOfCenturySwitch } { - incr y 1900 - } else { - incr y 2000 - } - } - dict set date era CE - dict set date year $y - dict set date month $m - dict set date dayOfMonth $d - if { $parseTime eq {} } { - set parseTime 0 - } - } - - # If the caller supplied a time zone in the string, it comes back as a - # two-element list; the first element is the number of minutes east of - # Greenwich, and the second is a Daylight Saving Time indicator (1 == yes, - # 0 == no, -1 == unknown). We make it into a time zone indicator of - # +-hhmm. - - if { [llength $parseZone] > 0 } { - lassign $parseZone minEast dstFlag - set timezone [FormatNumericTimeZone \ - [expr { 60 * $minEast + 3600 * $dstFlag }]] - SetupTimeZone $timezone - } - dict set date tzName $timezone - - # Assemble date, time, zone into seconds-from-epoch - - set date [GetJulianDayFromEraYearMonthDay $date[set date {}] 2361222] - if { $parseTime ne {} } { - dict set date secondOfDay $parseTime - } elseif { [llength $parseWeekday] != 0 - || [llength $parseOrdinalMonth] != 0 - || ( [llength $parseRel] != 0 - && ( [lindex $parseRel 0] != 0 - || [lindex $parseRel 1] != 0 ) ) } { - dict set date secondOfDay 0 - } - - dict set date localSeconds [expr { - -210866803200 - + ( 86400 * wide([dict get $date julianDay]) ) - + [dict get $date secondOfDay] - }] - dict set date tzName $timezone - set date [ConvertLocalToUTC $date[set date {}] $TZData($timezone) 2361222] - set seconds [dict get $date seconds] - - # Do relative times - - if { [llength $parseRel] > 0 } { - lassign $parseRel relMonth relDay relSecond - set seconds [add $seconds \ - $relMonth months $relDay days $relSecond seconds \ - -timezone $timezone -locale $locale] - } - - # Do relative weekday - - if { [llength $parseWeekday] > 0 } { - lassign $parseWeekday dayOrdinal dayOfWeek - set date2 [GetDateFields $seconds $TZData($timezone) 2361222] - dict set date2 era CE - set jdwkday [WeekdayOnOrBefore $dayOfWeek [expr { - [dict get $date2 julianDay] + 6 - }]] - incr jdwkday [expr { 7 * $dayOrdinal }] - if { $dayOrdinal > 0 } { - incr jdwkday -7 - } - dict set date2 secondOfDay \ - [expr { [dict get $date2 localSeconds] % 86400 }] - dict set date2 julianDay $jdwkday - dict set date2 localSeconds [expr { - -210866803200 - + ( 86400 * wide([dict get $date2 julianDay]) ) - + [dict get $date secondOfDay] - }] - dict set date2 tzName $timezone - set date2 [ConvertLocalToUTC $date2[set date2 {}] $TZData($timezone) \ - 2361222] - set seconds [dict get $date2 seconds] - - } - - # Do relative month - - if { [llength $parseOrdinalMonth] > 0 } { - lassign $parseOrdinalMonth monthOrdinal monthNumber - if { $monthOrdinal > 0 } { - set monthDiff [expr { $monthNumber - [dict get $date month] }] - if { $monthDiff <= 0 } { - incr monthDiff 12 - } - incr monthOrdinal -1 - } else { - set monthDiff [expr { [dict get $date month] - $monthNumber }] - if { $monthDiff >= 0 } { - incr monthDiff -12 - } - incr monthOrdinal - } - set seconds [add $seconds $monthOrdinal years $monthDiff months \ - -timezone $timezone -locale $locale] - } - - return $seconds -} - - -#---------------------------------------------------------------------- -# # ParseClockScanFormat -- # # Parses a format string given to [clock scan -format] @@ -2723,10 +2533,10 @@ proc ::tcl::clock::InterpretTwoDigitYear { date baseTime variable CurrentYearCentury variable YearOfCenturySwitch set yr [dict get $date $twoDigitField] - incr yr $CurrentYearCentury - if { $yr <= $YearOfCenturySwitch } { + if { $yr >= $YearOfCenturySwitch } { incr yr -100 } + incr yr $CurrentYearCentury dict set date $fourDigitField $yr return $date } @@ -3120,7 +2930,7 @@ proc ::tcl::clock::SetupTimeZone { timezone } { LoadZoneinfoFile [string range $timezone 1 end] }] } then { - dict set TimeZoneBad $timezone 1 + dict set TimeZoneBad $timezone 1 return -code error \ -errorcode [list CLOCK badTimeZone $timezone] \ "time zone \"$timezone\" not found" diff --git a/library/init.tcl b/library/init.tcl index 5e452b0..06a9459 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -178,7 +178,7 @@ if {[interp issafe]} { # Auto-loading stubs for 'clock.tcl' - foreach cmd {add format SetupTimeZone} { + foreach cmd {add format SetupTimeZone GetSystemTimeZone __org_scan} { proc ::tcl::clock::$cmd args { variable TclLibDir source -encoding utf-8 [file join $TclLibDir clock.tcl] diff --git a/tests/clock.test b/tests/clock.test index 6a0fecd..ecc6f5f 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -35662,7 +35662,7 @@ test clock-34.8 {clock scan tests} { } {Oct 23,1992 15:00 GMT} test clock-34.9 {clock scan tests} { list [catch {clock scan "Jan 12" -bad arg} msg] $msg -} {1 {bad option "-bad", must be -base, -format, -gmt, -locale or -timezone}} +} {1 {bad option "-bad": must be -format, -gmt, -locale, -timezone, or -base}} # The following two two tests test the two year date policy test clock-34.10 {clock scan tests} { set time [clock scan "1/1/71" -gmt true] @@ -35672,7 +35672,15 @@ test clock-34.11 {clock scan tests} { set time [clock scan "1/1/37" -gmt true] clock format $time -format {%b %d,%Y %H:%M GMT} -gmt true } {Jan 01,2037 00:00 GMT} - +test clock-34.11.1 {clock scan tests: same century switch} { + set times [clock scan "1/1/37" -gmt true] +} [clock scan "1/1/37" -format "%m/%d/%y" -gmt true] +test clock-34.11.2 {clock scan tests: same century switch} { + set times [clock scan "1/1/38" -gmt true] +} [clock scan "1/1/38" -format "%m/%d/%y" -gmt true] +test clock-34.11.3 {clock scan tests: same century switch} { + set times [clock scan "1/1/39" -gmt true] +} [clock scan "1/1/39" -format "%m/%d/%y" -gmt true] test clock-34.12 {clock scan, relative times} { set time [clock scan "Oct 23, 1992 -1 day"] clock format $time -format {%b %d, %Y} -- cgit v0.12