|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uplevel \#0 { |
|
package require msgcat 1.6 |
|
if { $::tcl_platform(platform) eq {windows} } { |
|
if { [catch { package require registry 1.1 }] } { |
|
namespace eval ::tcl::clock [list variable NoRegistry {}] |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
namespace eval ::tcl::clock \ |
|
[list variable LibDir [file dirname [info script]]] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace eval ::tcl::clock { |
|
|
|
|
|
|
|
namespace export format |
|
namespace export clicks |
|
namespace export microseconds |
|
namespace export milliseconds |
|
namespace export scan |
|
namespace export seconds |
|
namespace export add |
|
|
|
|
|
|
|
namespace import ::msgcat::mcload |
|
namespace import ::msgcat::mclocale |
|
namespace import ::msgcat::mc |
|
namespace import ::msgcat::mcpackagelocale |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::Initialize {} { |
|
|
|
rename ::tcl::clock::Initialize {} |
|
|
|
variable LibDir |
|
|
|
|
|
|
|
proc InitTZData {} { |
|
variable TZData |
|
array unset TZData |
|
set TZData(:Etc/GMT) { |
|
{-9223372036854775808 0 0 GMT} |
|
} |
|
set TZData(:GMT) $TZData(:Etc/GMT) |
|
set TZData(:Etc/UTC) { |
|
{-9223372036854775808 0 0 UTC} |
|
} |
|
set TZData(:UTC) $TZData(:Etc/UTC) |
|
set TZData(:localtime) {} |
|
} |
|
InitTZData |
|
|
|
mcpackagelocale set {} |
|
::msgcat::mcpackageconfig set mcfolder [file join $LibDir msgs] |
|
::msgcat::mcpackageconfig set unknowncmd "" |
|
::msgcat::mcpackageconfig set changecmd ChangeCurrentLocale |
|
|
|
|
|
|
|
::msgcat::mcmset {} { |
|
AM {am} |
|
BCE {B.C.E.} |
|
CE {C.E.} |
|
DATE_FORMAT {%m/%d/%Y} |
|
DATE_TIME_FORMAT {%a %b %e %H:%M:%S %Y} |
|
DAYS_OF_WEEK_ABBREV { |
|
Sun Mon Tue Wed Thu Fri Sat |
|
} |
|
DAYS_OF_WEEK_FULL { |
|
Sunday Monday Tuesday Wednesday Thursday Friday Saturday |
|
} |
|
GREGORIAN_CHANGE_DATE 2299161 |
|
LOCALE_DATE_FORMAT {%m/%d/%Y} |
|
LOCALE_DATE_TIME_FORMAT {%a %b %e %H:%M:%S %Y} |
|
LOCALE_ERAS {} |
|
LOCALE_NUMERALS { |
|
00 01 02 03 04 05 06 07 08 09 |
|
10 11 12 13 14 15 16 17 18 19 |
|
20 21 22 23 24 25 26 27 28 29 |
|
30 31 32 33 34 35 36 37 38 39 |
|
40 41 42 43 44 45 46 47 48 49 |
|
50 51 52 53 54 55 56 57 58 59 |
|
60 61 62 63 64 65 66 67 68 69 |
|
70 71 72 73 74 75 76 77 78 79 |
|
80 81 82 83 84 85 86 87 88 89 |
|
90 91 92 93 94 95 96 97 98 99 |
|
} |
|
LOCALE_TIME_FORMAT {%H:%M:%S} |
|
LOCALE_YEAR_FORMAT {%EC%Ey} |
|
MONTHS_ABBREV { |
|
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec |
|
} |
|
MONTHS_FULL { |
|
January February March |
|
April May June |
|
July August September |
|
October November December |
|
} |
|
PM {pm} |
|
TIME_FORMAT {%H:%M:%S} |
|
TIME_FORMAT_12 {%I:%M:%S %P} |
|
TIME_FORMAT_24 {%H:%M} |
|
TIME_FORMAT_24_SECS {%H:%M:%S} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
::msgcat::mcset it GREGORIAN_CHANGE_DATE 2299161 |
|
::msgcat::mcset es GREGORIAN_CHANGE_DATE 2299161 |
|
::msgcat::mcset pt GREGORIAN_CHANGE_DATE 2299161 |
|
::msgcat::mcset pl GREGORIAN_CHANGE_DATE 2299161 |
|
|
|
|
|
|
|
::msgcat::mcset fr GREGORIAN_CHANGE_DATE 2299227 |
|
|
|
|
|
|
|
|
|
::msgcat::mcset fr_BE GREGORIAN_CHANGE_DATE 2299238 |
|
::msgcat::mcset nl_BE GREGORIAN_CHANGE_DATE 2299238 |
|
|
|
|
|
|
|
::msgcat::mcset de_AT GREGORIAN_CHANGE_DATE 2299527 |
|
|
|
|
|
|
|
::msgcat::mcset hu GREGORIAN_CHANGE_DATE 2301004 |
|
|
|
|
|
|
|
::msgcat::mcset de_DE GREGORIAN_CHANGE_DATE 2342032 |
|
::msgcat::mcset nb GREGORIAN_CHANGE_DATE 2342032 |
|
::msgcat::mcset nn GREGORIAN_CHANGE_DATE 2342032 |
|
::msgcat::mcset no GREGORIAN_CHANGE_DATE 2342032 |
|
::msgcat::mcset da GREGORIAN_CHANGE_DATE 2342032 |
|
|
|
|
|
|
|
|
|
::msgcat::mcset nl GREGORIAN_CHANGE_DATE 2342165 |
|
|
|
|
|
|
|
::msgcat::mcset fr_CH GREGORIAN_CHANGE_DATE 2361342 |
|
::msgcat::mcset it_CH GREGORIAN_CHANGE_DATE 2361342 |
|
::msgcat::mcset de_CH GREGORIAN_CHANGE_DATE 2361342 |
|
|
|
|
|
|
|
::msgcat::mcset en GREGORIAN_CHANGE_DATE 2361222 |
|
|
|
|
|
|
|
::msgcat::mcset sv GREGORIAN_CHANGE_DATE 2361390 |
|
|
|
|
|
|
|
::msgcat::mcset ru GREGORIAN_CHANGE_DATE 2421639 |
|
|
|
|
|
|
|
|
|
::msgcat::mcset ro GREGORIAN_CHANGE_DATE 2422063 |
|
|
|
|
|
|
|
::msgcat::mcset el GREGORIAN_CHANGE_DATE 2423480 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variable ZoneinfoPaths {} |
|
foreach path { |
|
/usr/share/zoneinfo |
|
/usr/share/lib/zoneinfo |
|
/usr/lib/zoneinfo |
|
/usr/local/etc/zoneinfo |
|
} { |
|
if { [file isdirectory $path] } { |
|
lappend ZoneinfoPaths $path |
|
} |
|
} |
|
|
|
|
|
|
|
variable DataDir [file join $LibDir tzdata] |
|
|
|
|
|
|
|
variable DaysInRomanMonthInCommonYear \ |
|
{ 31 28 31 30 31 30 31 31 30 31 30 31 } |
|
variable DaysInRomanMonthInLeapYear \ |
|
{ 31 29 31 30 31 30 31 31 30 31 30 31 } |
|
variable DaysInPriorMonthsInCommonYear [list 0] |
|
variable DaysInPriorMonthsInLeapYear [list 0] |
|
set i 0 |
|
foreach j $DaysInRomanMonthInCommonYear { |
|
lappend DaysInPriorMonthsInCommonYear [incr i $j] |
|
} |
|
set i 0 |
|
foreach j $DaysInRomanMonthInLeapYear { |
|
lappend DaysInPriorMonthsInLeapYear [incr i $j] |
|
} |
|
|
|
|
|
|
|
variable Roddenberry 1946 |
|
|
|
|
|
|
|
variable MINWIDE -9223372036854775808 |
|
variable MAXWIDE 9223372036854775807 |
|
|
|
|
|
|
|
variable FEB_28 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variable WinZoneInfo [dict create {*}{ |
|
{-43200 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Pacific/Kwajalein |
|
{-39600 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Pacific/Midway |
|
{-36000 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Pacific/Honolulu |
|
{-32400 0 3600 0 11 0 1 2 0 0 0 0 3 0 2 2 0 0 0} :America/Anchorage |
|
{-28800 0 3600 0 11 0 1 2 0 0 0 0 3 0 2 2 0 0 0} :America/Los_Angeles |
|
{-28800 0 3600 0 10 0 5 2 0 0 0 0 4 0 1 2 0 0 0} :America/Tijuana |
|
{-25200 0 3600 0 11 0 1 2 0 0 0 0 3 0 2 2 0 0 0} :America/Denver |
|
{-25200 0 3600 0 10 0 5 2 0 0 0 0 4 0 1 2 0 0 0} :America/Chihuahua |
|
{-25200 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :America/Phoenix |
|
{-21600 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :America/Regina |
|
{-21600 0 3600 0 11 0 1 2 0 0 0 0 3 0 2 2 0 0 0} :America/Chicago |
|
{-21600 0 3600 0 10 0 5 2 0 0 0 0 4 0 1 2 0 0 0} :America/Mexico_City |
|
{-18000 0 3600 0 11 0 1 2 0 0 0 0 3 0 2 2 0 0 0} :America/New_York |
|
{-18000 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :America/Indianapolis |
|
{-14400 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :America/Caracas |
|
{-14400 0 3600 0 3 6 2 23 59 59 999 0 10 6 2 23 59 59 999} |
|
:America/Santiago |
|
{-14400 0 3600 0 2 0 5 2 0 0 0 0 11 0 1 2 0 0 0} :America/Manaus |
|
{-14400 0 3600 0 11 0 1 2 0 0 0 0 3 0 2 2 0 0 0} :America/Halifax |
|
{-12600 0 3600 0 10 0 5 2 0 0 0 0 4 0 1 2 0 0 0} :America/St_Johns |
|
{-10800 0 3600 0 2 0 2 2 0 0 0 0 10 0 3 2 0 0 0} :America/Sao_Paulo |
|
{-10800 0 3600 0 10 0 5 2 0 0 0 0 4 0 1 2 0 0 0} :America/Godthab |
|
{-10800 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :America/Buenos_Aires |
|
{-10800 0 3600 0 2 0 5 2 0 0 0 0 11 0 1 2 0 0 0} :America/Bahia |
|
{-10800 0 3600 0 3 0 2 2 0 0 0 0 10 0 1 2 0 0 0} :America/Montevideo |
|
{-7200 0 3600 0 9 0 5 2 0 0 0 0 3 0 5 2 0 0 0} :America/Noronha |
|
{-3600 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Atlantic/Azores |
|
{-3600 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Atlantic/Cape_Verde |
|
{0 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :UTC |
|
{0 0 3600 0 10 0 5 2 0 0 0 0 3 0 5 1 0 0 0} :Europe/London |
|
{3600 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Africa/Kinshasa |
|
{3600 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :CET |
|
{7200 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Africa/Harare |
|
{7200 0 3600 0 9 4 5 23 59 59 0 0 4 4 5 23 59 59 0} |
|
:Africa/Cairo |
|
{7200 0 3600 0 10 0 5 4 0 0 0 0 3 0 5 3 0 0 0} :Europe/Helsinki |
|
{7200 0 3600 0 9 0 3 2 0 0 0 0 3 5 5 2 0 0 0} :Asia/Jerusalem |
|
{7200 0 3600 0 9 0 5 1 0 0 0 0 3 0 5 0 0 0 0} :Europe/Bucharest |
|
{7200 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Europe/Athens |
|
{7200 0 3600 0 9 5 5 1 0 0 0 0 3 4 5 0 0 0 0} :Asia/Amman |
|
{7200 0 3600 0 10 6 5 23 59 59 999 0 3 0 5 0 0 0 0} |
|
:Asia/Beirut |
|
{7200 0 -3600 0 4 0 1 2 0 0 0 0 9 0 1 2 0 0 0} :Africa/Windhoek |
|
{10800 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Riyadh |
|
{10800 0 3600 0 10 0 1 4 0 0 0 0 4 0 1 3 0 0 0} :Asia/Baghdad |
|
{10800 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Europe/Moscow |
|
{12600 0 3600 0 9 2 4 2 0 0 0 0 3 0 1 2 0 0 0} :Asia/Tehran |
|
{14400 0 3600 0 10 0 5 5 0 0 0 0 3 0 5 4 0 0 0} :Asia/Baku |
|
{14400 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Muscat |
|
{14400 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Asia/Tbilisi |
|
{16200 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Kabul |
|
{18000 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Karachi |
|
{18000 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Asia/Yekaterinburg |
|
{19800 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Calcutta |
|
{20700 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Katmandu |
|
{21600 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Dhaka |
|
{21600 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Asia/Novosibirsk |
|
{23400 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Rangoon |
|
{25200 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Bangkok |
|
{25200 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Asia/Krasnoyarsk |
|
{28800 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Chongqing |
|
{28800 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Asia/Irkutsk |
|
{32400 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Asia/Tokyo |
|
{32400 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Asia/Yakutsk |
|
{34200 0 3600 0 3 0 5 3 0 0 0 0 10 0 5 2 0 0 0} :Australia/Adelaide |
|
{34200 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Australia/Darwin |
|
{36000 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Australia/Brisbane |
|
{36000 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Asia/Vladivostok |
|
{36000 0 3600 0 3 0 5 3 0 0 0 0 10 0 1 2 0 0 0} :Australia/Hobart |
|
{36000 0 3600 0 3 0 5 3 0 0 0 0 10 0 5 2 0 0 0} :Australia/Sydney |
|
{39600 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Pacific/Noumea |
|
{43200 0 3600 0 3 0 3 3 0 0 0 0 10 0 1 2 0 0 0} :Pacific/Auckland |
|
{43200 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Pacific/Fiji |
|
{46800 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :Pacific/Tongatapu |
|
}] |
|
|
|
|
|
|
|
|
|
|
|
|
|
variable DateParseActions { |
|
|
|
{ seconds } 0 {} |
|
|
|
{ julianDay } 1 {} |
|
|
|
{ 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 } 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 } 3 { |
|
dict set date era CE |
|
dict set date iso8601Year \ |
|
[expr { 100 * [dict get $date iso8601Century] |
|
+ [dict get $date iso8601YearOfCentury] }] |
|
set date [GetJulianDayFromEraYearWeekDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
|
|
{ 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 } 4 { |
|
set date [InterpretTwoDigitYear $date[set date {}] $baseTime] |
|
dict set date era CE |
|
set date [GetJulianDayFromEraYearDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
{ iso8601YearOfCentury iso8601Week dayOfWeek } 4 { |
|
set date [InterpretTwoDigitYear \ |
|
$date[set date {}] $baseTime \ |
|
iso8601YearOfCentury iso8601Year] |
|
dict set date era CE |
|
set date [GetJulianDayFromEraYearWeekDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
|
|
{ month dayOfMonth } 5 { |
|
set date [AssignBaseYear $date[set date {}] \ |
|
$baseTime $timeZone $changeover] |
|
set date [GetJulianDayFromEraYearMonthDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
{ dayOfYear } 5 { |
|
set date [AssignBaseYear $date[set date {}] \ |
|
$baseTime $timeZone $changeover] |
|
set date [GetJulianDayFromEraYearDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
{ iso8601Week dayOfWeek } 5 { |
|
set date [AssignBaseIso8601Year $date[set date {}] \ |
|
$baseTime $timeZone $changeover] |
|
set date [GetJulianDayFromEraYearWeekDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
|
|
{ dayOfMonth } 6 { |
|
set date [AssignBaseMonth $date[set date {}] \ |
|
$baseTime $timeZone $changeover] |
|
set date [GetJulianDayFromEraYearMonthDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
|
|
{ dayOfWeek } 7 { |
|
set date [AssignBaseWeek $date[set date {}] \ |
|
$baseTime $timeZone $changeover] |
|
set date [GetJulianDayFromEraYearWeekDay $date[set date {}] \ |
|
$changeover] |
|
} |
|
|
|
{} 8 { |
|
set date [AssignBaseJulianDay $date[set date {}] \ |
|
$baseTime $timeZone $changeover] |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
variable TimeParseActions { |
|
|
|
seconds 1 {} |
|
|
|
{ hourAMPM minute second amPmIndicator } 2 { |
|
dict set date secondOfDay [InterpretHMSP $date] |
|
} |
|
{ hour minute second } 2 { |
|
dict set date secondOfDay [InterpretHMS $date] |
|
} |
|
|
|
{ hourAMPM minute amPmIndicator } 3 { |
|
dict set date second 0 |
|
dict set date secondOfDay [InterpretHMSP $date] |
|
} |
|
{ hour minute } 3 { |
|
dict set date second 0 |
|
dict set date secondOfDay [InterpretHMS $date] |
|
} |
|
|
|
{ hourAMPM amPmIndicator } 4 { |
|
dict set date minute 0 |
|
dict set date second 0 |
|
dict set date secondOfDay [InterpretHMSP $date] |
|
} |
|
{ hour } 4 { |
|
dict set date minute 0 |
|
dict set date second 0 |
|
dict set date secondOfDay [InterpretHMS $date] |
|
} |
|
|
|
{ } 5 { |
|
dict set date secondOfDay 0 |
|
} |
|
} |
|
|
|
|
|
|
|
variable LegacyTimeZone [dict create \ |
|
gmt +0000 \ |
|
ut +0000 \ |
|
utc +0000 \ |
|
bst +0100 \ |
|
wet +0000 \ |
|
wat -0100 \ |
|
at -0200 \ |
|
nft -0330 \ |
|
nst -0330 \ |
|
ndt -0230 \ |
|
ast -0400 \ |
|
adt -0300 \ |
|
est -0500 \ |
|
edt -0400 \ |
|
cst -0600 \ |
|
cdt -0500 \ |
|
mst -0700 \ |
|
mdt -0600 \ |
|
pst -0800 \ |
|
pdt -0700 \ |
|
yst -0900 \ |
|
ydt -0800 \ |
|
hst -1000 \ |
|
hdt -0900 \ |
|
cat -1000 \ |
|
ahst -1000 \ |
|
nt -1100 \ |
|
idlw -1200 \ |
|
cet +0100 \ |
|
cest +0200 \ |
|
met +0100 \ |
|
mewt +0100 \ |
|
mest +0200 \ |
|
swt +0100 \ |
|
sst +0200 \ |
|
fwt +0100 \ |
|
fst +0200 \ |
|
eet +0200 \ |
|
eest +0300 \ |
|
bt +0300 \ |
|
it +0330 \ |
|
zp4 +0400 \ |
|
zp5 +0500 \ |
|
ist +0530 \ |
|
zp6 +0600 \ |
|
wast +0700 \ |
|
wadt +0800 \ |
|
jt +0730 \ |
|
cct +0800 \ |
|
jst +0900 \ |
|
kst +0900 \ |
|
cast +0930 \ |
|
jdt +1000 \ |
|
kdt +1000 \ |
|
cadt +1030 \ |
|
east +1000 \ |
|
eadt +1030 \ |
|
gst +1000 \ |
|
nzt +1200 \ |
|
nzst +1200 \ |
|
nzdt +1300 \ |
|
idle +1200 \ |
|
a +0100 \ |
|
b +0200 \ |
|
c +0300 \ |
|
d +0400 \ |
|
e +0500 \ |
|
f +0600 \ |
|
g +0700 \ |
|
h +0800 \ |
|
i +0900 \ |
|
k +1000 \ |
|
l +1100 \ |
|
m +1200 \ |
|
n -0100 \ |
|
o -0200 \ |
|
p -0300 \ |
|
q -0400 \ |
|
r -0500 \ |
|
s -0600 \ |
|
t -0700 \ |
|
u -0800 \ |
|
v -0900 \ |
|
w -1000 \ |
|
x -1100 \ |
|
y -1200 \ |
|
z +0000 \ |
|
] |
|
|
|
|
|
|
|
variable LocaleNumeralCache {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variable TimeZoneBad {} |
|
|
|
|
|
|
|
variable TZData |
|
|
|
|
|
|
|
|
|
variable FormatProc |
|
|
|
|
|
} |
|
::tcl::clock::Initialize |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::format { args } { |
|
|
|
variable FormatProc |
|
variable TZData |
|
|
|
lassign [ParseFormatArgs {*}$args] format locale timezone |
|
set locale [string tolower $locale] |
|
set clockval [lindex $args 0] |
|
|
|
|
|
|
|
if {$timezone eq ""} { |
|
set timezone [GetSystemTimeZone] |
|
} |
|
if {![info exists TZData($timezone)]} { |
|
if {[catch {SetupTimeZone $timezone} retval opts]} { |
|
dict unset opts -errorinfo |
|
return -options $opts $retval |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
set procName formatproc'$format'$locale |
|
set procName [namespace current]::[string map {: {\:} \\ {\\}} $procName] |
|
if {[info exists FormatProc($procName)]} { |
|
set procName $FormatProc($procName) |
|
} else { |
|
set FormatProc($procName) \ |
|
[ParseClockFormatFormat $procName $format $locale] |
|
} |
|
|
|
return [$procName $clockval $timezone] |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ParseClockFormatFormat {procName format locale} { |
|
|
|
if {[namespace which $procName] ne {}} { |
|
return $procName |
|
} |
|
|
|
|
|
|
|
EnterLocale $locale |
|
|
|
|
|
|
|
try { |
|
return [ParseClockFormatFormat2 $format $locale $procName] |
|
} trap CLOCK {result opts} { |
|
dict unset opts -errorinfo |
|
return -options $opts $result |
|
} |
|
} |
|
|
|
proc ::tcl::clock::ParseClockFormatFormat2 {format locale procName} { |
|
set didLocaleEra 0 |
|
set didLocaleNumerals 0 |
|
set preFormatCode \ |
|
[string map [list @GREGORIAN_CHANGE_DATE@ \ |
|
[mc GREGORIAN_CHANGE_DATE]] \ |
|
{ |
|
variable TZData |
|
set date [GetDateFields $clockval \ |
|
$TZData($timezone) \ |
|
@GREGORIAN_CHANGE_DATE@] |
|
}] |
|
set formatString {} |
|
set substituents {} |
|
set state {} |
|
|
|
set format [LocalizeFormat $locale $format] |
|
|
|
foreach char [split $format {}] { |
|
switch -exact -- $state { |
|
{} { |
|
if { [string equal % $char] } { |
|
set state percent |
|
} else { |
|
append formatString $char |
|
} |
|
} |
|
percent { # Character following a '%' character |
|
set state {} |
|
switch -exact -- $char { |
|
% { # A literal character, '%' |
|
append formatString %% |
|
} |
|
a { # Day of week, abbreviated |
|
append formatString %s |
|
append substituents \ |
|
[string map \ |
|
[list @DAYS_OF_WEEK_ABBREV@ \ |
|
[list [mc DAYS_OF_WEEK_ABBREV]]] \ |
|
{ [lindex @DAYS_OF_WEEK_ABBREV@ \ |
|
[expr {[dict get $date dayOfWeek] \ |
|
% 7}]]}] |
|
} |
|
A { # Day of week, spelt out. |
|
append formatString %s |
|
append substituents \ |
|
[string map \ |
|
[list @DAYS_OF_WEEK_FULL@ \ |
|
[list [mc DAYS_OF_WEEK_FULL]]] \ |
|
{ [lindex @DAYS_OF_WEEK_FULL@ \ |
|
[expr {[dict get $date dayOfWeek] \ |
|
% 7}]]}] |
|
} |
|
b - h { # Name of month, abbreviated. |
|
append formatString %s |
|
append substituents \ |
|
[string map \ |
|
[list @MONTHS_ABBREV@ \ |
|
[list [mc MONTHS_ABBREV]]] \ |
|
{ [lindex @MONTHS_ABBREV@ \ |
|
[expr {[dict get $date month]-1}]]}] |
|
} |
|
B { # Name of month, spelt out |
|
append formatString %s |
|
append substituents \ |
|
[string map \ |
|
[list @MONTHS_FULL@ \ |
|
[list [mc MONTHS_FULL]]] \ |
|
{ [lindex @MONTHS_FULL@ \ |
|
[expr {[dict get $date month]-1}]]}] |
|
} |
|
C { # Century number |
|
append formatString %02d |
|
append substituents \ |
|
{ [expr {[dict get $date year] / 100}]} |
|
} |
|
d { # Day of month, with leading zero |
|
append formatString %02d |
|
append substituents { [dict get $date dayOfMonth]} |
|
} |
|
e { # Day of month, without leading zero |
|
append formatString %2d |
|
append substituents { [dict get $date dayOfMonth]} |
|
} |
|
E { # Format group in a locale-dependent |
|
|
|
set state percentE |
|
if {!$didLocaleEra} { |
|
append preFormatCode \ |
|
[string map \ |
|
[list @LOCALE_ERAS@ \ |
|
[list [mc LOCALE_ERAS]]] \ |
|
{ |
|
set date [GetLocaleEra \ |
|
$date[set date {}] \ |
|
@LOCALE_ERAS@]}] \n |
|
set didLocaleEra 1 |
|
} |
|
if {!$didLocaleNumerals} { |
|
append preFormatCode \ |
|
[list set localeNumerals \ |
|
[mc LOCALE_NUMERALS]] \n |
|
set didLocaleNumerals 1 |
|
} |
|
} |
|
g { # Two-digit year relative to ISO8601 |
|
|
|
append formatString %02d |
|
append substituents \ |
|
{ [expr { [dict get $date iso8601Year] % 100 }]} |
|
} |
|
G { # Four-digit year relative to ISO8601 |
|
|
|
append formatString %02d |
|
append substituents { [dict get $date iso8601Year]} |
|
} |
|
H { # Hour in the 24-hour day, leading zero |
|
append formatString %02d |
|
append substituents \ |
|
{ [expr { [dict get $date localSeconds] \ |
|
/ 3600 % 24}]} |
|
} |
|
I { # Hour AM/PM, with leading zero |
|
append formatString %02d |
|
append substituents \ |
|
{ [expr { ( ( ( [dict get $date localSeconds] \ |
|
% 86400 ) \ |
|
+ 86400 \ |
|
- 3600 ) \ |
|
/ 3600 ) \ |
|
% 12 + 1 }] } |
|
} |
|
j { # Day of year (001-366) |
|
append formatString %03d |
|
append substituents { [dict get $date dayOfYear]} |
|
} |
|
J { # Julian Day Number |
|
append formatString %07ld |
|
append substituents { [dict get $date julianDay]} |
|
} |
|
k { # Hour (0-23), no leading zero |
|
append formatString %2d |
|
append substituents \ |
|
{ [expr { [dict get $date localSeconds] |
|
/ 3600 |
|
% 24 }]} |
|
} |
|
l { # Hour (12-11), no leading zero |
|
append formatString %2d |
|
append substituents \ |
|
{ [expr { ( ( ( [dict get $date localSeconds] |
|
% 86400 ) |
|
+ 86400 |
|
- 3600 ) |
|
/ 3600 ) |
|
% 12 + 1 }]} |
|
} |
|
m { # Month number, leading zero |
|
append formatString %02d |
|
append substituents { [dict get $date month]} |
|
} |
|
M { # Minute of the hour, leading zero |
|
append formatString %02d |
|
append substituents \ |
|
{ [expr { [dict get $date localSeconds] |
|
/ 60 |
|
% 60 }]} |
|
} |
|
n { # A literal newline |
|
append formatString \n |
|
} |
|
N { # Month number, no leading zero |
|
append formatString %2d |
|
append substituents { [dict get $date month]} |
|
} |
|
O { # A format group in the locale's |
|
|
|
set state percentO |
|
if {!$didLocaleNumerals} { |
|
append preFormatCode \ |
|
[list set localeNumerals \ |
|
[mc LOCALE_NUMERALS]] \n |
|
set didLocaleNumerals 1 |
|
} |
|
} |
|
p { # Localized 'AM' or 'PM' indicator |
|
|
|
append formatString %s |
|
append preFormatCode \ |
|
[list set AM [string toupper [mc AM]]] \n \ |
|
[list set PM [string toupper [mc PM]]] \n |
|
append substituents \ |
|
{ [expr {(([dict get $date localSeconds] |
|
% 86400) < 43200) ? |
|
$AM : $PM}]} |
|
} |
|
P { # Localized 'AM' or 'PM' indicator |
|
append formatString %s |
|
append preFormatCode \ |
|
[list set am [mc AM]] \n \ |
|
[list set pm [mc PM]] \n |
|
append substituents \ |
|
{ [expr {(([dict get $date localSeconds] |
|
% 86400) < 43200) ? |
|
$am : $pm}]} |
|
|
|
} |
|
Q { # Hi, Jeff! |
|
append formatString %s |
|
append substituents { [FormatStarDate $date]} |
|
} |
|
s { # Seconds from the Posix Epoch |
|
append formatString %s |
|
append substituents { [dict get $date seconds]} |
|
} |
|
S { # Second of the minute, with |
|
|
|
append formatString %02d |
|
append substituents \ |
|
{ [expr { [dict get $date localSeconds] |
|
% 60 }]} |
|
} |
|
t { # A literal tab character |
|
append formatString \t |
|
} |
|
u { # Day of the week (1-Monday, 7-Sunday) |
|
append formatString %1d |
|
append substituents { [dict get $date dayOfWeek]} |
|
} |
|
U { # Week of the year (00-53). The |
|
|
|
|
|
append formatString %02d |
|
append preFormatCode { |
|
set dow [dict get $date dayOfWeek] |
|
if { $dow == 7 } { |
|
set dow 0 |
|
} |
|
incr dow |
|
set UweekNumber \ |
|
[expr { ( [dict get $date dayOfYear] |
|
- $dow + 7 ) |
|
/ 7 }] |
|
} |
|
append substituents { $UweekNumber} |
|
} |
|
V { # The ISO8601 week number |
|
append formatString %02d |
|
append substituents { [dict get $date iso8601Week]} |
|
} |
|
w { # Day of the week (0-Sunday, |
|
|
|
append formatString %1d |
|
append substituents \ |
|
{ [expr { [dict get $date dayOfWeek] % 7 }]} |
|
} |
|
W { # Week of the year (00-53). The first |
|
|
|
|
|
append preFormatCode { |
|
set WweekNumber \ |
|
[expr { ( [dict get $date dayOfYear] |
|
- [dict get $date dayOfWeek] |
|
+ 7 ) |
|
/ 7 }] |
|
} |
|
append formatString %02d |
|
append substituents { $WweekNumber} |
|
} |
|
y { # The two-digit year of the century |
|
append formatString %02d |
|
append substituents \ |
|
{ [expr { [dict get $date year] % 100 }]} |
|
} |
|
Y { # The four-digit year |
|
append formatString %04d |
|
append substituents { [dict get $date year]} |
|
} |
|
z { # The time zone as hours and minutes |
|
|
|
append formatString %s |
|
append substituents { [FormatNumericTimeZone \ |
|
[dict get $date tzOffset]]} |
|
} |
|
Z { # The name of the time zone |
|
append formatString %s |
|
append substituents { [dict get $date tzName]} |
|
} |
|
% { # A literal percent character |
|
append formatString %% |
|
} |
|
default { # An unknown escape sequence |
|
append formatString %% $char |
|
} |
|
} |
|
} |
|
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]} |
|
} |
|
y { # Locale-dependent year of the era |
|
append preFormatCode { |
|
set y [dict get $date localeYear] |
|
if { $y >= 0 && $y < 100 } { |
|
set Eyear [lindex $localeNumerals $y] |
|
} else { |
|
set Eyear $y |
|
} |
|
} |
|
append formatString %s |
|
append substituents { $Eyear} |
|
} |
|
default { # Unknown %E format group |
|
append formatString %%E $char |
|
} |
|
} |
|
} |
|
percentO { # Character following %O |
|
set state {} |
|
switch -exact -- $char { |
|
d - e { # Day of the month in alternative |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[dict get $date dayOfMonth]]} |
|
} |
|
H - k { # Hour of the day in alternative |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[expr { [dict get $date localSeconds] |
|
/ 3600 |
|
% 24 }]]} |
|
} |
|
I - l { # Hour (12-11) AM/PM in alternative |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[expr { ( ( ( [dict get $date localSeconds] |
|
% 86400 ) |
|
+ 86400 |
|
- 3600 ) |
|
/ 3600 ) |
|
% 12 + 1 }]]} |
|
} |
|
m { # Month number in alternative numerals |
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals [dict get $date month]]} |
|
} |
|
M { # Minute of the hour in alternative |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[expr { [dict get $date localSeconds] |
|
/ 60 |
|
% 60 }]]} |
|
} |
|
S { # Second of the minute in alternative |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[expr { [dict get $date localSeconds] |
|
% 60 }]]} |
|
} |
|
u { # Day of the week (Monday=1,Sunday=7) |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[dict get $date dayOfWeek]]} |
|
} |
|
w { # Day of the week (Sunday=0,Saturday=6) |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[expr { [dict get $date dayOfWeek] % 7 }]]} |
|
} |
|
y { # Year of the century in alternative |
|
|
|
append formatString %s |
|
append substituents \ |
|
{ [lindex $localeNumerals \ |
|
[expr { [dict get $date year] % 100 }]]} |
|
} |
|
default { # Unknown format group |
|
append formatString %%O $char |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
switch -exact -- $state { |
|
percent { |
|
append formatString %% |
|
} |
|
percentE { |
|
append retval %%E |
|
} |
|
percentO { |
|
append retval %%O |
|
} |
|
} |
|
|
|
proc $procName {clockval timezone} " |
|
$preFormatCode |
|
return \[::format [list $formatString] $substituents\] |
|
" |
|
|
|
|
|
|
|
return $procName |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::scan { args } { |
|
|
|
set format {} |
|
|
|
|
|
|
|
if { [llength $args] < 1 || [llength $args] % 2 != 1 } { |
|
set cmdName "clock scan" |
|
return -code error \ |
|
-errorcode [list CLOCK wrongNumArgs] \ |
|
"wrong \# args: should be\ |
|
\"$cmdName string\ |
|
?-base seconds?\ |
|
?-format string? ?-gmt boolean?\ |
|
?-locale LOCALE? ?-timezone ZONE?\"" |
|
} |
|
|
|
|
|
|
|
set base [clock seconds] |
|
set string [lindex $args 0] |
|
set format {} |
|
set gmt 0 |
|
set locale c |
|
set timezone [GetSystemTimeZone] |
|
|
|
|
|
|
|
foreach { flag value } [lreplace $args 0 0] { |
|
set saw($flag) {} |
|
switch -exact -- $flag { |
|
-b - -ba - -bas - -base { |
|
set base $value |
|
} |
|
-f - -fo - -for - -form - -forma - -format { |
|
set format $value |
|
} |
|
-g - -gm - -gmt { |
|
set gmt $value |
|
} |
|
-l - -lo - -loc - -loca - -local - -locale { |
|
set locale [string tolower $value] |
|
} |
|
-t - -ti - -tim - -time - -timez - -timezo - -timezon - -timezone { |
|
set timezone $value |
|
} |
|
default { |
|
return -code error \ |
|
-errorcode [list CLOCK badOption $flag] \ |
|
"bad option \"$flag\",\ |
|
must be -base, -format, -gmt, -locale or -timezone" |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
if { [info exists saw(-gmt)] && [info exists saw(-timezone)] } { |
|
return -code error \ |
|
-errorcode [list CLOCK gmtWithTimezone] \ |
|
"cannot use -gmt and -timezone in same call" |
|
} |
|
if { [catch { expr { wide($base) } } result] } { |
|
return -code error "expected integer but got \"$base\"" |
|
} |
|
if { ![string is boolean -strict $gmt] } { |
|
return -code error "expected boolean value but got \"$gmt\"" |
|
} elseif { $gmt } { |
|
set timezone :GMT |
|
} |
|
|
|
if { ![info exists saw(-format)] } { |
|
|
|
|
|
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] |
|
} |
|
|
|
|
|
|
|
EnterLocale $locale |
|
|
|
try { |
|
|
|
|
|
set scanner [ParseClockScanFormat $format $locale] |
|
return [$scanner $string $base $timezone] |
|
} trap CLOCK {result opts} { |
|
|
|
dict unset opts -errorinfo |
|
return -options $opts $result |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::FreeScan { string base timezone locale } { |
|
|
|
variable TZData |
|
|
|
|
|
|
|
try { |
|
SetupTimeZone $timezone |
|
} on error {retval opts} { |
|
dict unset opts -errorinfo |
|
return -options $opts $retval |
|
} |
|
|
|
|
|
|
|
|
|
set date [GetDateFields $base $TZData($timezone) 2361222] |
|
dict set date secondOfDay [expr { |
|
[dict get $date localSeconds] % 86400 |
|
}] |
|
|
|
|
|
|
|
|
|
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 { [llength $parseDate] > 0 } { |
|
lassign $parseDate y m d |
|
if { $y < 100 } { |
|
if { $y >= 39 } { |
|
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 { [llength $parseZone] > 0 } { |
|
lassign $parseZone minEast dstFlag |
|
set timezone [FormatNumericTimeZone \ |
|
[expr { 60 * $minEast + 3600 * $dstFlag }]] |
|
SetupTimeZone $timezone |
|
} |
|
dict set date tzName $timezone |
|
|
|
|
|
|
|
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] |
|
|
|
|
|
|
|
if { [llength $parseRel] > 0 } { |
|
lassign $parseRel relMonth relDay relSecond |
|
set seconds [add $seconds \ |
|
$relMonth months $relDay days $relSecond seconds \ |
|
-timezone $timezone -locale $locale] |
|
} |
|
|
|
|
|
|
|
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] |
|
|
|
} |
|
|
|
|
|
|
|
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 |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ParseClockScanFormat {formatString locale} { |
|
|
|
|
|
|
|
set procName scanproc'$formatString'$locale |
|
set procName [namespace current]::[string map {: {\:} \\ {\\}} $procName] |
|
if { [namespace which $procName] != {} } { |
|
return $procName |
|
} |
|
|
|
variable DateParseActions |
|
variable TimeParseActions |
|
|
|
|
|
|
|
set formatString [LocalizeFormat $locale $formatString] |
|
|
|
|
|
|
|
regsub -all {[[:space:]]+} $formatString { } formatString |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
set re {^[[:space:]]*} |
|
set captureCount 0 |
|
set postcode {} |
|
set fieldSet [dict create] |
|
set fieldCount 0 |
|
set postSep {} |
|
set state {} |
|
|
|
foreach c [split $formatString {}] { |
|
switch -exact -- $state { |
|
{} { |
|
if { $c eq "%" } { |
|
set state % |
|
} elseif { $c eq " " } { |
|
append re {[[:space:]]+} |
|
} else { |
|
if { ! [string is alnum $c] } { |
|
append re "\\" |
|
} |
|
append re $c |
|
} |
|
} |
|
% { |
|
set state {} |
|
switch -exact -- $c { |
|
% { |
|
append re % |
|
} |
|
{ } { |
|
append re "\[\[:space:\]\]*" |
|
} |
|
a - A { # Day of week, in words |
|
set l {} |
|
foreach \ |
|
i {7 1 2 3 4 5 6} \ |
|
abr [mc DAYS_OF_WEEK_ABBREV] \ |
|
full [mc DAYS_OF_WEEK_FULL] { |
|
dict set l [string tolower $abr] $i |
|
dict set l [string tolower $full] $i |
|
incr i |
|
} |
|
lassign [UniquePrefixRegexp $l] regex lookup |
|
append re ( $regex ) |
|
dict set fieldSet dayOfWeek [incr fieldCount] |
|
append postcode "dict set date dayOfWeek \[" \ |
|
"dict get " [list $lookup] " " \ |
|
\[ {string tolower $field} [incr captureCount] \] \ |
|
"\]\n" |
|
} |
|
b - B - h { # Name of month |
|
set i 0 |
|
set l {} |
|
foreach \ |
|
abr [mc MONTHS_ABBREV] \ |
|
full [mc MONTHS_FULL] { |
|
incr i |
|
dict set l [string tolower $abr] $i |
|
dict set l [string tolower $full] $i |
|
} |
|
lassign [UniquePrefixRegexp $l] regex lookup |
|
append re ( $regex ) |
|
dict set fieldSet month [incr fieldCount] |
|
append postcode "dict set date month \[" \ |
|
"dict get " [list $lookup] \ |
|
" " \[ {string tolower $field} \ |
|
[incr captureCount] \] \ |
|
"\]\n" |
|
} |
|
C { # Gregorian century |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet century [incr fieldCount] |
|
append postcode "dict set date century \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
d - e { # Day of month |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet dayOfMonth [incr fieldCount] |
|
append postcode "dict set date dayOfMonth \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
E { # Prefix for locale-specific codes |
|
set state %E |
|
} |
|
g { # ISO8601 2-digit year |
|
append re \\s*(\\d\\d) |
|
dict set fieldSet iso8601YearOfCentury \ |
|
[incr fieldCount] |
|
append postcode \ |
|
"dict set date iso8601YearOfCentury \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
G { # ISO8601 4-digit year |
|
append re \\s*(\\d\\d)(\\d\\d) |
|
dict set fieldSet iso8601Century [incr fieldCount] |
|
dict set fieldSet iso8601YearOfCentury \ |
|
[incr fieldCount] |
|
append postcode \ |
|
"dict set date iso8601Century \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" \ |
|
"dict set date iso8601YearOfCentury \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
H - k { # Hour of day |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet hour [incr fieldCount] |
|
append postcode "dict set date hour \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
I - l { # Hour, AM/PM |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet hourAMPM [incr fieldCount] |
|
append postcode "dict set date hourAMPM \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
j { # Day of year |
|
append re \\s*(\\d\\d?\\d?) |
|
dict set fieldSet dayOfYear [incr fieldCount] |
|
append postcode "dict set date dayOfYear \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
J { # Julian Day Number |
|
append re \\s*(\\d+) |
|
dict set fieldSet julianDay [incr fieldCount] |
|
append postcode "dict set date julianDay \[" \ |
|
"::scan \$field" [incr captureCount] " %ld" \ |
|
"\]\n" |
|
} |
|
m - N { # Month number |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet month [incr fieldCount] |
|
append postcode "dict set date month \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
M { # Minute |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet minute [incr fieldCount] |
|
append postcode "dict set date minute \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
n { # Literal newline |
|
append re \\n |
|
} |
|
O { # Prefix for locale numerics |
|
set state %O |
|
} |
|
p - P { # AM/PM indicator |
|
set l [list [string tolower [mc AM]] 0 \ |
|
[string tolower [mc PM]] 1] |
|
lassign [UniquePrefixRegexp $l] regex lookup |
|
append re ( $regex ) |
|
dict set fieldSet amPmIndicator [incr fieldCount] |
|
append postcode "dict set date amPmIndicator \[" \ |
|
"dict get " [list $lookup] " \[string tolower " \ |
|
"\$field" \ |
|
[incr captureCount] \ |
|
"\]\]\n" |
|
} |
|
Q { # Hi, Jeff! |
|
append re {Stardate\s+([-+]?\d+)(\d\d\d)[.](\d)} |
|
incr captureCount |
|
dict set fieldSet seconds [incr fieldCount] |
|
append postcode {dict set date seconds } \[ \ |
|
{ParseStarDate $field} [incr captureCount] \ |
|
{ $field} [incr captureCount] \ |
|
{ $field} [incr captureCount] \ |
|
\] \n |
|
} |
|
s { # Seconds from Posix Epoch |
|
|
|
|
|
|
|
append re {\s*([-+]?\d+)} |
|
dict set fieldSet seconds [incr fieldCount] |
|
append postcode {dict set date seconds } \[ \ |
|
{ScanWide $field} [incr captureCount] \] \n |
|
} |
|
S { # Second |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet second [incr fieldCount] |
|
append postcode "dict set date second \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
t { # Literal tab character |
|
append re \\t |
|
} |
|
u - w { # Day number within week, 0 or 7 == Sun |
|
|
|
append re \\s*(\\d) |
|
dict set fieldSet dayOfWeek [incr fieldCount] |
|
append postcode {::scan $field} [incr captureCount] \ |
|
{ %d dow} \n \ |
|
{ |
|
if { $dow == 0 } { |
|
set dow 7 |
|
} elseif { $dow > 7 } { |
|
return -code error \ |
|
-errorcode [list CLOCK badDayOfWeek] \ |
|
"day of week is greater than 7" |
|
} |
|
dict set date dayOfWeek $dow |
|
} |
|
} |
|
U { # Week of year. The first Sunday of |
|
|
|
|
|
append re \\s*\\d\\d? |
|
} |
|
V { # Week of ISO8601 year |
|
|
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet iso8601Week [incr fieldCount] |
|
append postcode "dict set date iso8601Week \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
W { # Week of the year (00-53). The first |
|
|
|
|
|
|
|
append re \\s*\\d\\d? |
|
} |
|
y { # Two-digit Gregorian year |
|
append re \\s*(\\d\\d?) |
|
dict set fieldSet yearOfCentury [incr fieldCount] |
|
append postcode "dict set date yearOfCentury \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
Y { # 4-digit Gregorian year |
|
append re \\s*(\\d\\d)(\\d\\d) |
|
dict set fieldSet century [incr fieldCount] |
|
dict set fieldSet yearOfCentury [incr fieldCount] |
|
append postcode \ |
|
"dict set date century \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" \ |
|
"dict set date yearOfCentury \[" \ |
|
"::scan \$field" [incr captureCount] " %d" \ |
|
"\]\n" |
|
} |
|
z - Z { # Time zone name |
|
append re {(?:([-+]\d\d(?::?\d\d(?::?\d\d)?)?)|([[:alnum:]]{1,4}))} |
|
dict set fieldSet tzName [incr fieldCount] |
|
append postcode \ |
|
{if } \{ { $field} [incr captureCount] \ |
|
{ ne "" } \} { } \{ \n \ |
|
{dict set date tzName $field} \ |
|
$captureCount \n \ |
|
\} { else } \{ \n \ |
|
{dict set date tzName } \[ \ |
|
{ConvertLegacyTimeZone $field} \ |
|
[incr captureCount] \] \n \ |
|
\} \n \ |
|
} |
|
% { # Literal percent character |
|
append re % |
|
} |
|
default { |
|
append re % |
|
if { ! [string is alnum $c] } { |
|
append re \\ |
|
} |
|
append re $c |
|
} |
|
} |
|
} |
|
%E { |
|
switch -exact -- $c { |
|
C { # Locale-dependent era |
|
set d {} |
|
foreach triple [mc LOCALE_ERAS] { |
|
lassign $triple t symbol year |
|
dict set d [string tolower $symbol] $year |
|
} |
|
lassign [UniquePrefixRegexp $d] regex lookup |
|
append re (?: $regex ) |
|
} |
|
E { |
|
set l {} |
|
dict set l [string tolower [mc BCE]] BCE |
|
dict set l [string tolower [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 |
|
lassign [UniquePrefixRegexp $l] regex lookup |
|
append re ( $regex ) |
|
dict set fieldSet era [incr fieldCount] |
|
append postcode "dict set date era \["\ |
|
"dict get " [list $lookup] \ |
|
{ } \[ {string tolower $field} \ |
|
[incr captureCount] \] \ |
|
"\]\n" |
|
} |
|
y { # Locale-dependent year of the era |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
incr captureCount |
|
} |
|
default { |
|
append re %E |
|
if { ! [string is alnum $c] } { |
|
append re \\ |
|
} |
|
append re $c |
|
} |
|
} |
|
set state {} |
|
} |
|
%O { |
|
switch -exact -- $c { |
|
d - e { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet dayOfMonth [incr fieldCount] |
|
append postcode "dict set date dayOfMonth \[" \ |
|
"dict get " [list $lookup] " \$field" \ |
|
[incr captureCount] \ |
|
"\]\n" |
|
} |
|
H - k { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet hour [incr fieldCount] |
|
append postcode "dict set date hour \[" \ |
|
"dict get " [list $lookup] " \$field" \ |
|
[incr captureCount] \ |
|
"\]\n" |
|
} |
|
I - l { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet hourAMPM [incr fieldCount] |
|
append postcode "dict set date hourAMPM \[" \ |
|
"dict get " [list $lookup] " \$field" \ |
|
[incr captureCount] \ |
|
"\]\n" |
|
} |
|
m { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet month [incr fieldCount] |
|
append postcode "dict set date month \[" \ |
|
"dict get " [list $lookup] " \$field" \ |
|
[incr captureCount] \ |
|
"\]\n" |
|
} |
|
M { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet minute [incr fieldCount] |
|
append postcode "dict set date minute \[" \ |
|
"dict get " [list $lookup] " \$field" \ |
|
[incr captureCount] \ |
|
"\]\n" |
|
} |
|
S { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet second [incr fieldCount] |
|
append postcode "dict set date second \[" \ |
|
"dict get " [list $lookup] " \$field" \ |
|
[incr captureCount] \ |
|
"\]\n" |
|
} |
|
u - w { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet dayOfWeek [incr fieldCount] |
|
append postcode "set dow \[dict get " [list $lookup] \ |
|
{ $field} [incr captureCount] \] \n \ |
|
{ |
|
if { $dow == 0 } { |
|
set dow 7 |
|
} elseif { $dow > 7 } { |
|
return -code error \ |
|
-errorcode [list CLOCK badDayOfWeek] \ |
|
"day of week is greater than 7" |
|
} |
|
dict set date dayOfWeek $dow |
|
} |
|
} |
|
y { |
|
lassign [LocaleNumeralMatcher $locale] regex lookup |
|
append re $regex |
|
dict set fieldSet yearOfCentury [incr fieldCount] |
|
append postcode {dict set date yearOfCentury } \[ \ |
|
{dict get } [list $lookup] { $field} \ |
|
[incr captureCount] \] \n |
|
} |
|
default { |
|
append re %O |
|
if { ! [string is alnum $c] } { |
|
append re \\ |
|
} |
|
append re $c |
|
} |
|
} |
|
set state {} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
append re $state \\s*\$ |
|
|
|
|
|
|
|
set procBody {} |
|
append procBody "variable ::tcl::clock::TZData" \n |
|
append procBody "if \{ !\[ regexp -nocase [list $re] \$string ->" |
|
for { set i 1 } { $i <= $captureCount } { incr i } { |
|
append procBody " " field $i |
|
} |
|
append procBody "\] \} \{" \n |
|
append procBody { |
|
return -code error -errorcode [list CLOCK badInputString] \ |
|
{input string does not match supplied format} |
|
} |
|
append procBody \}\n |
|
append procBody "set date \[dict create\]" \n |
|
append procBody {dict set date tzName $timeZone} \n |
|
append procBody $postcode |
|
append procBody [list set changeover [mc GREGORIAN_CHANGE_DATE]] \n |
|
|
|
|
|
|
|
|
|
if { ![dict exists $fieldSet seconds] |
|
&& ![dict exists $fieldSet starDate] } { |
|
if { [dict exists $fieldSet tzName] } { |
|
append procBody { |
|
set timeZone [dict get $date tzName] |
|
} |
|
} |
|
append procBody { |
|
::tcl::clock::SetupTimeZone $timeZone |
|
} |
|
} |
|
|
|
|
|
|
|
append procBody [MakeParseCodeFromFields $fieldSet $DateParseActions] |
|
|
|
|
|
|
|
append procBody [MakeParseCodeFromFields $fieldSet $TimeParseActions] |
|
|
|
|
|
|
|
|
|
|
|
if { ![dict exists $fieldSet seconds] |
|
&& ![dict exists $fieldSet starDate] } { |
|
append procBody { |
|
if { [dict get $date julianDay] > 5373484 } { |
|
return -code error -errorcode [list CLOCK dateTooLarge] \ |
|
"requested date too large to represent" |
|
} |
|
dict set date localSeconds [expr { |
|
-210866803200 |
|
+ ( 86400 * wide([dict get $date julianDay]) ) |
|
+ [dict get $date secondOfDay] |
|
}] |
|
} |
|
|
|
|
|
|
|
append procBody { |
|
set date [::tcl::clock::ConvertLocalToUTC $date[set date {}] \ |
|
$TZData($timeZone) $changeover] |
|
} |
|
} |
|
|
|
|
|
|
|
append procBody {return [dict get $date seconds]} \n |
|
|
|
proc $procName { string baseTime timeZone } $procBody |
|
|
|
|
|
|
|
return $procName |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::LocaleNumeralMatcher {l} { |
|
variable LocaleNumeralCache |
|
|
|
if { ![dict exists $LocaleNumeralCache $l] } { |
|
set d {} |
|
set i 0 |
|
set sep \( |
|
foreach n [mc LOCALE_NUMERALS] { |
|
dict set d $n $i |
|
regsub -all {[^[:alnum:]]} $n \\\\& subex |
|
append re $sep $subex |
|
set sep | |
|
incr i |
|
} |
|
append re \) |
|
dict set LocaleNumeralCache $l [list $re $d] |
|
} |
|
return [dict get $LocaleNumeralCache $l] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::UniquePrefixRegexp { data } { |
|
|
|
|
|
|
|
|
|
|
|
set prefixMapping [dict create] |
|
set successors [dict create {} {}] |
|
|
|
|
|
|
|
foreach { key value } $data { |
|
|
|
|
|
set prefix {} |
|
foreach char [split $key {}] { |
|
set oldPrefix $prefix |
|
dict set successors $oldPrefix $char {} |
|
append prefix $char |
|
|
|
|
|
|
|
|
|
dict lappend prefixMapping $prefix $value |
|
if { ![dict exists $successors $prefix] } { |
|
dict set successors $prefix {} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
set uniquePrefixMapping {} |
|
dict for { key valueList } $prefixMapping { |
|
if { [llength $valueList] == 1 } { |
|
dict set uniquePrefixMapping $key [lindex $valueList 0] |
|
} |
|
} |
|
foreach { key value } $data { |
|
dict set uniquePrefixMapping $key $value |
|
} |
|
|
|
|
|
|
|
return [list \ |
|
[MakeUniquePrefixRegexp $successors $uniquePrefixMapping {}] \ |
|
$uniquePrefixMapping] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::MakeUniquePrefixRegexp { successors |
|
uniquePrefixMapping |
|
prefixString } { |
|
|
|
|
|
|
|
set schars [lsort -ascii [dict keys [dict get $successors $prefixString]]] |
|
if { [llength $schars] == 0 } { |
|
return {} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
set re {} |
|
if { |
|
[dict exists $uniquePrefixMapping $prefixString] |
|
|| [llength $schars] > 1 |
|
} then { |
|
append re "(?:" |
|
} |
|
|
|
|
|
|
|
set sep "" |
|
foreach { c } $schars { |
|
set nextPrefix $prefixString$c |
|
regsub -all {[^[:alnum:]]} $c \\\\& rechar |
|
append re $sep $rechar \ |
|
[MakeUniquePrefixRegexp \ |
|
$successors $uniquePrefixMapping $nextPrefix] |
|
set sep | |
|
} |
|
|
|
|
|
|
|
|
|
|
|
if { [dict exists $uniquePrefixMapping $prefixString] } { |
|
append re ")?" |
|
} elseif { [llength $schars] > 1 } { |
|
append re ")" |
|
} |
|
|
|
return $re |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::MakeParseCodeFromFields { dateFields parseActions } { |
|
|
|
set currPrio 999 |
|
set currFieldPos [list] |
|
set currCodeBurst { |
|
error "in ::tcl::clock::MakeParseCodeFromFields: can't happen" |
|
} |
|
|
|
foreach { fieldSet prio parseAction } $parseActions { |
|
|
|
|
|
|
|
if { $prio > $currPrio } { |
|
break |
|
} |
|
|
|
|
|
|
|
|
|
set fieldPos [list] |
|
set ok true |
|
foreach field $fieldSet { |
|
if { ! [dict exists $dateFields $field] } { |
|
set ok 0 |
|
break |
|
} |
|
lappend fieldPos [dict get $dateFields $field] |
|
} |
|
|
|
|
|
if { !$ok } { |
|
continue |
|
} |
|
|
|
|
|
|
|
set fPos [lsort -integer -decreasing $fieldPos] |
|
|
|
if { $prio == $currPrio } { |
|
foreach currPos $currFieldPos newPos $fPos { |
|
if { |
|
![string is integer $newPos] |
|
|| ![string is integer $currPos] |
|
|| $newPos > $currPos |
|
} then { |
|
break |
|
} |
|
if { $newPos < $currPos } { |
|
set ok 0 |
|
break |
|
} |
|
} |
|
} |
|
if { !$ok } { |
|
continue |
|
} |
|
|
|
|
|
|
|
set currPrio $prio |
|
set currFieldPos $fPos |
|
set currCodeBurst $parseAction |
|
} |
|
|
|
return $currCodeBurst |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::EnterLocale { locale } { |
|
if { $locale eq {system} } { |
|
if { $::tcl_platform(platform) ne {windows} } { |
|
|
|
|
|
|
|
set locale current |
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
mcpackagelocale set [mclocale] |
|
|
|
|
|
|
|
|
|
set locale [mclocale]_windows |
|
if { ! [mcpackagelocale present $locale] } { |
|
LoadWindowsDateTimeFormats $locale |
|
} |
|
} |
|
} |
|
if { $locale eq {current}} { |
|
set locale [mclocale] |
|
} |
|
|
|
mcpackagelocale set $locale |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::LoadWindowsDateTimeFormats { locale } { |
|
|
|
|
|
variable NoRegistry |
|
if { [info exists NoRegistry] } return |
|
|
|
if { ![catch { |
|
registry get "HKEY_CURRENT_USER\\Control Panel\\International" \ |
|
sShortDate |
|
} string] } { |
|
set quote {} |
|
set datefmt {} |
|
foreach { unquoted quoted } [split $string '] { |
|
append datefmt $quote [string map { |
|
dddd %A |
|
ddd %a |
|
dd %d |
|
d %e |
|
MMMM %B |
|
MMM %b |
|
MM %m |
|
M %N |
|
yyyy %Y |
|
yy %y |
|
y %y |
|
gg {} |
|
} $unquoted] |
|
if { $quoted eq {} } { |
|
set quote ' |
|
} else { |
|
set quote $quoted |
|
} |
|
} |
|
::msgcat::mcset $locale DATE_FORMAT $datefmt |
|
} |
|
|
|
if { ![catch { |
|
registry get "HKEY_CURRENT_USER\\Control Panel\\International" \ |
|
sLongDate |
|
} string] } { |
|
set quote {} |
|
set ldatefmt {} |
|
foreach { unquoted quoted } [split $string '] { |
|
append ldatefmt $quote [string map { |
|
dddd %A |
|
ddd %a |
|
dd %d |
|
d %e |
|
MMMM %B |
|
MMM %b |
|
MM %m |
|
M %N |
|
yyyy %Y |
|
yy %y |
|
y %y |
|
gg {} |
|
} $unquoted] |
|
if { $quoted eq {} } { |
|
set quote ' |
|
} else { |
|
set quote $quoted |
|
} |
|
} |
|
::msgcat::mcset $locale LOCALE_DATE_FORMAT $ldatefmt |
|
} |
|
|
|
if { ![catch { |
|
registry get "HKEY_CURRENT_USER\\Control Panel\\International" \ |
|
sTimeFormat |
|
} string] } { |
|
set quote {} |
|
set timefmt {} |
|
foreach { unquoted quoted } [split $string '] { |
|
append timefmt $quote [string map { |
|
HH %H |
|
H %k |
|
hh %I |
|
h %l |
|
mm %M |
|
m %M |
|
ss %S |
|
s %S |
|
tt %p |
|
t %p |
|
} $unquoted] |
|
if { $quoted eq {} } { |
|
set quote ' |
|
} else { |
|
set quote $quoted |
|
} |
|
} |
|
::msgcat::mcset $locale TIME_FORMAT $timefmt |
|
} |
|
|
|
catch { |
|
::msgcat::mcset $locale DATE_TIME_FORMAT "$datefmt $timefmt" |
|
} |
|
catch { |
|
::msgcat::mcset $locale LOCALE_DATE_TIME_FORMAT "$ldatefmt $timefmt" |
|
} |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::LocalizeFormat { locale format } { |
|
|
|
|
|
set key FORMAT_$format |
|
|
|
if { [::msgcat::mcexists -exactlocale -exactnamespace $key] } { |
|
return [mc $key] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
set list { |
|
%% %% |
|
%D %m/%d/%Y |
|
%+ {%a %b %e %H:%M:%S %Z %Y} |
|
} |
|
lappend list %EY [string map $list [mc LOCALE_YEAR_FORMAT]] |
|
lappend list %T [string map $list [mc TIME_FORMAT_24_SECS]] |
|
lappend list %R [string map $list [mc TIME_FORMAT_24]] |
|
lappend list %r [string map $list [mc TIME_FORMAT_12]] |
|
lappend list %X [string map $list [mc TIME_FORMAT]] |
|
lappend list %EX [string map $list [mc LOCALE_TIME_FORMAT]] |
|
lappend list %x [string map $list [mc DATE_FORMAT]] |
|
lappend list %Ex [string map $list [mc LOCALE_DATE_FORMAT]] |
|
lappend list %c [string map $list [mc DATE_TIME_FORMAT]] |
|
lappend list %Ec [string map $list [mc LOCALE_DATE_TIME_FORMAT]] |
|
set format [string map $list $format] |
|
|
|
::msgcat::mcset $locale $key $format |
|
return $format |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::FormatNumericTimeZone { z } { |
|
if { $z < 0 } { |
|
set z [expr { - $z }] |
|
set retval - |
|
} else { |
|
set retval + |
|
} |
|
append retval [::format %02d [expr { $z / 3600 }]] |
|
set z [expr { $z % 3600 }] |
|
append retval [::format %02d [expr { $z / 60 }]] |
|
set z [expr { $z % 60 }] |
|
if { $z != 0 } { |
|
append retval [::format %02d $z] |
|
} |
|
return $retval |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::FormatStarDate { date } { |
|
variable Roddenberry |
|
|
|
|
|
|
|
set doy [expr { [dict get $date dayOfYear] - 1 }] |
|
|
|
|
|
|
|
set lp [IsGregorianLeapYear $date] |
|
|
|
|
|
|
|
if { $lp } { |
|
set fractYear [expr { 1000 * $doy / 366 }] |
|
} else { |
|
set fractYear [expr { 1000 * $doy / 365 }] |
|
} |
|
|
|
|
|
|
|
return [::format "Stardate %02d%03d.%1d" \ |
|
[expr { [dict get $date year] - $Roddenberry }] \ |
|
$fractYear \ |
|
[expr { [dict get $date localSeconds] % 86400 |
|
/ ( 86400 / 10 ) }]] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ParseStarDate { year fractYear fractDay } { |
|
variable Roddenberry |
|
|
|
|
|
|
|
set date [dict create \ |
|
gregorian 1 \ |
|
era CE \ |
|
year [expr { $year + $Roddenberry }] \ |
|
dayOfYear [expr { $fractYear * 365 / 1000 + 1 }]] |
|
set date [GetJulianDayFromGregorianEraYearDay $date[set date {}]] |
|
|
|
|
|
|
|
set lp [IsGregorianLeapYear $date] |
|
|
|
|
|
|
|
|
|
if { $lp } { |
|
dict set date dayOfYear \ |
|
[expr { $fractYear * 366 / 1000 + 1 }] |
|
} else { |
|
dict set date dayOfYear \ |
|
[expr { $fractYear * 365 / 1000 + 1 }] |
|
} |
|
dict unset date julianDay |
|
dict unset date gregorian |
|
set date [GetJulianDayFromGregorianEraYearDay $date[set date {}]] |
|
|
|
return [expr { |
|
86400 * [dict get $date julianDay] |
|
- 210866803200 |
|
+ ( 86400 / 10 ) * $fractDay |
|
}] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ScanWide { str } { |
|
set count [::scan $str {%ld %c} result junk] |
|
if { $count != 1 } { |
|
return -code error -errorcode [list CLOCK notAnInteger $str] \ |
|
"\"$str\" is not an integer" |
|
} |
|
if { [incr result 0] != $str } { |
|
return -code error -errorcode [list CLOCK integervalueTooLarge] \ |
|
"integer value too large to represent" |
|
} |
|
return $result |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::InterpretTwoDigitYear { date baseTime |
|
{ twoDigitField yearOfCentury } |
|
{ fourDigitField year } } { |
|
set yr [dict get $date $twoDigitField] |
|
if { $yr <= 37 } { |
|
dict set date $fourDigitField [expr { $yr + 2000 }] |
|
} else { |
|
dict set date $fourDigitField [expr { $yr + 1900 }] |
|
} |
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::AssignBaseYear { date baseTime timezone changeover } { |
|
variable TZData |
|
|
|
|
|
|
|
|
|
set date2 [GetDateFields $baseTime $TZData($timezone) $changeover] |
|
|
|
|
|
|
|
dict set date era [dict get $date2 era] |
|
dict set date year [dict get $date2 year] |
|
|
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::AssignBaseIso8601Year {date baseTime timeZone changeover} { |
|
variable TZData |
|
|
|
|
|
|
|
set date2 [GetDateFields $baseTime $TZData($timeZone) $changeover] |
|
|
|
|
|
|
|
dict set date era CE |
|
dict set date iso8601Year [dict get $date2 iso8601Year] |
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::AssignBaseMonth {date baseTime timezone changeover} { |
|
variable TZData |
|
|
|
|
|
|
|
set date2 [GetDateFields $baseTime $TZData($timezone) $changeover] |
|
dict set date era [dict get $date2 era] |
|
dict set date year [dict get $date2 year] |
|
dict set date month [dict get $date2 month] |
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::AssignBaseWeek {date baseTime timeZone changeover} { |
|
variable TZData |
|
|
|
|
|
|
|
set date2 [GetDateFields $baseTime $TZData($timeZone) $changeover] |
|
|
|
|
|
|
|
dict set date era CE |
|
dict set date iso8601Year [dict get $date2 iso8601Year] |
|
dict set date iso8601Week [dict get $date2 iso8601Week] |
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::AssignBaseJulianDay { date baseTime timeZone changeover } { |
|
variable TZData |
|
|
|
|
|
|
|
set date2 [GetDateFields $baseTime $TZData($timeZone) $changeover] |
|
dict set date julianDay [dict get $date2 julianDay] |
|
|
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::InterpretHMSP { date } { |
|
set hr [dict get $date hourAMPM] |
|
if { $hr == 12 } { |
|
set hr 0 |
|
} |
|
if { [dict get $date amPmIndicator] } { |
|
incr hr 12 |
|
} |
|
dict set date hour $hr |
|
return [InterpretHMS $date[set date {}]] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::InterpretHMS { date } { |
|
return [expr { |
|
( [dict get $date hour] * 60 |
|
+ [dict get $date minute] ) * 60 |
|
+ [dict get $date second] |
|
}] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::GetSystemTimeZone {} { |
|
variable CachedSystemTimeZone |
|
variable TimeZoneBad |
|
|
|
if {[set result [getenv TCL_TZ]] ne {}} { |
|
set timezone $result |
|
} elseif {[set result [getenv TZ]] ne {}} { |
|
set timezone $result |
|
} |
|
if {![info exists timezone]} { |
|
|
|
|
|
if { [info exists CachedSystemTimeZone] } { |
|
set timezone $CachedSystemTimeZone |
|
} elseif { $::tcl_platform(platform) eq {windows} } { |
|
set timezone [GuessWindowsTimeZone] |
|
} elseif { [file exists /etc/localtime] |
|
&& ![catch {ReadZoneinfoFile \ |
|
Tcl/Localtime /etc/localtime}] } { |
|
set timezone :Tcl/Localtime |
|
} else { |
|
set timezone :localtime |
|
} |
|
set CachedSystemTimeZone $timezone |
|
} |
|
if { ![dict exists $TimeZoneBad $timezone] } { |
|
dict set TimeZoneBad $timezone [catch {SetupTimeZone $timezone}] |
|
} |
|
if { [dict get $TimeZoneBad $timezone] } { |
|
return :localtime |
|
} else { |
|
return $timezone |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ConvertLegacyTimeZone { tzname } { |
|
variable LegacyTimeZone |
|
|
|
set tzname [string tolower $tzname] |
|
if { ![dict exists $LegacyTimeZone $tzname] } { |
|
return -code error -errorcode [list CLOCK badTZName $tzname] \ |
|
"time zone \"$tzname\" not found" |
|
} |
|
return [dict get $LegacyTimeZone $tzname] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::SetupTimeZone { timezone } { |
|
variable TZData |
|
|
|
if {! [info exists TZData($timezone)] } { |
|
variable MINWIDE |
|
if { $timezone eq {:localtime} } { |
|
|
|
|
|
} elseif { |
|
[regexp {^([-+])(\d\d)(?::?(\d\d)(?::?(\d\d))?)?} $timezone \ |
|
-> s hh mm ss] |
|
} then { |
|
|
|
|
|
::scan $hh %d hh |
|
if { $mm eq {} } { |
|
set mm 0 |
|
} else { |
|
::scan $mm %d mm |
|
} |
|
if { $ss eq {} } { |
|
set ss 0 |
|
} else { |
|
::scan $ss %d ss |
|
} |
|
set offset [expr { ( $hh * 60 + $mm ) * 60 + $ss }] |
|
if { $s eq {-} } { |
|
set offset [expr { - $offset }] |
|
} |
|
set TZData($timezone) [list [list $MINWIDE $offset -1 $timezone]] |
|
|
|
} elseif { [string index $timezone 0] eq {:} } { |
|
|
|
|
|
if { |
|
[catch { |
|
LoadTimeZoneFile [string range $timezone 1 end] |
|
}] && [catch { |
|
LoadZoneinfoFile [string range $timezone 1 end] |
|
}] |
|
} then { |
|
return -code error \ |
|
-errorcode [list CLOCK badTimeZone $timezone] \ |
|
"time zone \"$timezone\" not found" |
|
} |
|
} elseif { ![catch {ParsePosixTimeZone $timezone} tzfields] } { |
|
|
|
|
|
if { [catch {ProcessPosixTimeZone $tzfields} data opts] } { |
|
if { [lindex [dict get $opts -errorcode] 0] eq {CLOCK} } { |
|
dict unset opts -errorinfo |
|
} |
|
return -options $opts $data |
|
} else { |
|
set TZData($timezone) $data |
|
} |
|
|
|
} else { |
|
|
|
|
|
|
|
if { [catch { LoadTimeZoneFile $timezone }] |
|
&& [catch { LoadZoneinfoFile $timezone } - opts] } { |
|
dict unset opts -errorinfo |
|
return -options $opts "time zone $timezone not found" |
|
} |
|
set TZData($timezone) $TZData(:$timezone) |
|
} |
|
} |
|
|
|
return |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::GuessWindowsTimeZone {} { |
|
variable WinZoneInfo |
|
variable NoRegistry |
|
variable TimeZoneBad |
|
|
|
if { [info exists NoRegistry] } { |
|
return :localtime |
|
} |
|
|
|
|
|
|
|
if { [catch { |
|
set rpath HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\TimeZoneInformation |
|
set data [list \ |
|
[expr { -60 |
|
* [registry get $rpath Bias] }] \ |
|
[expr { -60 |
|
* [registry get $rpath StandardBias] }] \ |
|
[expr { -60 \ |
|
* [registry get $rpath DaylightBias] }]] |
|
set stdtzi [registry get $rpath StandardStart] |
|
foreach ind {0 2 14 4 6 8 10 12} { |
|
binary scan $stdtzi @${ind}s val |
|
lappend data $val |
|
} |
|
set daytzi [registry get $rpath DaylightStart] |
|
foreach ind {0 2 14 4 6 8 10 12} { |
|
binary scan $daytzi @${ind}s val |
|
lappend data $val |
|
} |
|
}] } { |
|
|
|
|
|
return :localtime |
|
} |
|
|
|
|
|
|
|
|
|
|
|
if { [dict exists $WinZoneInfo $data] } { |
|
set tzname [dict get $WinZoneInfo $data] |
|
if { ! [dict exists $TimeZoneBad $tzname] } { |
|
dict set TimeZoneBad $tzname [catch {SetupTimeZone $tzname}] |
|
} |
|
} else { |
|
set tzname {} |
|
} |
|
if { $tzname eq {} || [dict get $TimeZoneBad $tzname] } { |
|
lassign $data \ |
|
bias stdBias dstBias \ |
|
stdYear stdMonth stdDayOfWeek stdDayOfMonth \ |
|
stdHour stdMinute stdSecond stdMillisec \ |
|
dstYear dstMonth dstDayOfWeek dstDayOfMonth \ |
|
dstHour dstMinute dstSecond dstMillisec |
|
set stdDelta [expr { $bias + $stdBias }] |
|
set dstDelta [expr { $bias + $dstBias }] |
|
if { $stdDelta <= 0 } { |
|
set stdSignum + |
|
set stdDelta [expr { - $stdDelta }] |
|
set dispStdSignum - |
|
} else { |
|
set stdSignum - |
|
set dispStdSignum + |
|
} |
|
set hh [::format %02d [expr { $stdDelta / 3600 }]] |
|
set mm [::format %02d [expr { ($stdDelta / 60 ) % 60 }]] |
|
set ss [::format %02d [expr { $stdDelta % 60 }]] |
|
set tzname {} |
|
append tzname < $dispStdSignum $hh $mm > $stdSignum $hh : $mm : $ss |
|
if { $stdMonth >= 0 } { |
|
if { $dstDelta <= 0 } { |
|
set dstSignum + |
|
set dstDelta [expr { - $dstDelta }] |
|
set dispDstSignum - |
|
} else { |
|
set dstSignum - |
|
set dispDstSignum + |
|
} |
|
set hh [::format %02d [expr { $dstDelta / 3600 }]] |
|
set mm [::format %02d [expr { ($dstDelta / 60 ) % 60 }]] |
|
set ss [::format %02d [expr { $dstDelta % 60 }]] |
|
append tzname < $dispDstSignum $hh $mm > $dstSignum $hh : $mm : $ss |
|
if { $dstYear == 0 } { |
|
append tzname ,M $dstMonth . $dstDayOfMonth . $dstDayOfWeek |
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
return :localtime |
|
} |
|
append tzname / [::format %02d $dstHour] \ |
|
: [::format %02d $dstMinute] \ |
|
: [::format %02d $dstSecond] |
|
if { $stdYear == 0 } { |
|
append tzname ,M $stdMonth . $stdDayOfMonth . $stdDayOfWeek |
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
return :localtime |
|
} |
|
append tzname / [::format %02d $stdHour] \ |
|
: [::format %02d $stdMinute] \ |
|
: [::format %02d $stdSecond] |
|
} |
|
dict set WinZoneInfo $data $tzname |
|
} |
|
|
|
return [dict get $WinZoneInfo $data] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::LoadTimeZoneFile { fileName } { |
|
variable DataDir |
|
variable TZData |
|
|
|
if { [info exists TZData($fileName)] } { |
|
return |
|
} |
|
|
|
|
|
|
|
|
|
|
|
if { ![regexp {^[[.-.][:alpha:]_]+(?:/[[.-.][:alpha:]_]+)*$} $fileName] } { |
|
return -code error \ |
|
-errorcode [list CLOCK badTimeZone $:fileName] \ |
|
"time zone \":$fileName\" not valid" |
|
} |
|
try { |
|
source -encoding utf-8 [file join $DataDir $fileName] |
|
} on error {} { |
|
return -code error \ |
|
-errorcode [list CLOCK badTimeZone :$fileName] \ |
|
"time zone \":$fileName\" not found" |
|
} |
|
return |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::LoadZoneinfoFile { fileName } { |
|
variable ZoneinfoPaths |
|
|
|
|
|
|
|
|
|
|
|
if { ![regexp {^[[.-.][:alpha:]_]+(?:/[[.-.][:alpha:]_]+)*$} $fileName] } { |
|
return -code error \ |
|
-errorcode [list CLOCK badTimeZone $:fileName] \ |
|
"time zone \":$fileName\" not valid" |
|
} |
|
foreach d $ZoneinfoPaths { |
|
set fname [file join $d $fileName] |
|
if { [file readable $fname] && [file isfile $fname] } { |
|
break |
|
} |
|
unset fname |
|
} |
|
ReadZoneinfoFile $fileName $fname |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ReadZoneinfoFile {fileName fname} { |
|
variable MINWIDE |
|
variable TZData |
|
if { ![file exists $fname] } { |
|
return -code error "$fileName not found" |
|
} |
|
|
|
if { [file size $fname] > 262144 } { |
|
return -code error "$fileName too big" |
|
} |
|
|
|
|
|
|
|
set f [open $fname r] |
|
fconfigure $f -translation binary |
|
set d [read $f] |
|
close $f |
|
|
|
|
|
|
|
|
|
binary scan $d a4a1x15IIIIII \ |
|
magic version nIsGMT nIsStd nLeap nTime nType nChar |
|
set seek 44 |
|
set ilen 4 |
|
set iformat I |
|
if { $magic != {TZif} } { |
|
return -code error "$fileName not a time zone information file" |
|
} |
|
if { $nType > 255 } { |
|
return -code error "$fileName contains too many time types" |
|
} |
|
|
|
if { $nLeap != 0 } { |
|
return -code error "$fileName contains leap seconds" |
|
} |
|
|
|
|
|
|
|
|
|
if {$version eq "2"} { |
|
set seek [expr { |
|
44 |
|
+ 5 * $nTime |
|
+ 6 * $nType |
|
+ 4 * $nLeap |
|
+ $nIsStd |
|
+ $nIsGMT |
|
+ $nChar |
|
}] |
|
binary scan $d @${seek}a4a1x15IIIIII \ |
|
magic version nIsGMT nIsStd nLeap nTime nType nChar |
|
if {$magic ne {TZif}} { |
|
return -code error "seek address $seek miscomputed, magic = $magic" |
|
} |
|
set iformat W |
|
set ilen 8 |
|
incr seek 44 |
|
} |
|
|
|
|
|
|
|
|
|
|
|
binary scan $d @${seek}${iformat}${nTime}c${nTime} times tempCodes |
|
incr seek [expr { ($ilen + 1) * $nTime }] |
|
set times [linsert $times 0 $MINWIDE] |
|
set codes {} |
|
foreach c $tempCodes { |
|
lappend codes [expr { $c & 0xff }] |
|
} |
|
set codes [linsert $codes 0 0] |
|
|
|
|
|
|
|
|
|
|
|
for { set i 0 } { $i < $nType } { incr i } { |
|
binary scan $d @${seek}Icc gmtOff isDst abbrInd |
|
lappend types [list $gmtOff $isDst $abbrInd] |
|
incr seek 6 |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
binary scan $d @${seek}a${nChar} abbrs |
|
incr seek ${nChar} |
|
set abbrList [split $abbrs \0] |
|
set i 0 |
|
set abbrevs {} |
|
foreach a $abbrList { |
|
for {set j 0} {$j <= [string length $a]} {incr j} { |
|
dict set abbrevs $i [string range $a $j end] |
|
incr i |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
set r {} |
|
set lastTime $MINWIDE |
|
foreach t $times c $codes { |
|
if { $t < $lastTime } { |
|
return -code error "$fileName has times out of order" |
|
} |
|
set lastTime $t |
|
lassign [lindex $types $c] gmtoff isDst abbrInd |
|
set abbrev [dict get $abbrevs $abbrInd] |
|
lappend r [list $t $gmtoff $isDst $abbrev] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
if {$version eq {2}} { |
|
set seek [expr {$seek + 8 * $nLeap + $nIsStd + $nIsGMT + 1}] |
|
set last [string first \n $d $seek] |
|
set posix [string range $d $seek [expr {$last-1}]] |
|
if {[llength $posix] > 0} { |
|
set posixFields [ParsePosixTimeZone $posix] |
|
foreach tuple [ProcessPosixTimeZone $posixFields] { |
|
lassign $tuple t gmtoff isDst abbrev |
|
if {$t > $lastTime} { |
|
lappend r $tuple |
|
} |
|
} |
|
} |
|
} |
|
|
|
set TZData(:$fileName) $r |
|
|
|
return |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ParsePosixTimeZone { tz } { |
|
if {[regexp -expanded -nocase -- { |
|
^ |
|
|
|
([[:alpha:]]+ | <[-+[:alnum:]]+>) |
|
|
|
([-+]?) |
|
|
|
([[:digit:]]{1,2}) |
|
(?: |
|
|
|
: ([[:digit:]]{1,2}) |
|
(?: |
|
|
|
: ([[:digit:]]{1,2} ) |
|
)? |
|
)? |
|
(?: |
|
|
|
([[:alpha:]]+ | <[-+[:alnum:]]+>) |
|
(?: |
|
(?: |
|
|
|
([-+]?) |
|
|
|
([[:digit:]]{1,2}) |
|
(?: |
|
|
|
: ([[:digit:]]{1,2}) |
|
(?: |
|
|
|
: ([[:digit:]]{1,2}) |
|
)? |
|
)? |
|
)? |
|
(?: |
|
, |
|
(?: |
|
|
|
( J ? ) ( [[:digit:]]+ ) |
|
| M |
|
|
|
( [[:digit:]] + ) |
|
[.] ( [[:digit:]] + ) |
|
[.] ( [[:digit:]] + ) |
|
) |
|
(?: |
|
|
|
/ ( [[:digit:]]{1,2} ) |
|
(?: |
|
|
|
: ( [[:digit:]]{1,2} ) |
|
(?: |
|
|
|
: ( [[:digit:]]{1,2} ) |
|
)? |
|
)? |
|
)? |
|
, |
|
(?: |
|
|
|
( J ? ) ( [[:digit:]]+ ) |
|
| M |
|
|
|
( [[:digit:]] + ) |
|
[.] ( [[:digit:]] + ) |
|
[.] ( [[:digit:]] + ) |
|
) |
|
(?: |
|
|
|
/ ( [[:digit:]]{1,2} ) |
|
(?: |
|
|
|
: ( [[:digit:]]{1,2} ) |
|
(?: |
|
|
|
: ( [[:digit:]]{1,2} ) |
|
)? |
|
)? |
|
)? |
|
)? |
|
)? |
|
)? |
|
$ |
|
} $tz -> x(stdName) x(stdSignum) x(stdHours) x(stdMinutes) x(stdSeconds) \ |
|
x(dstName) x(dstSignum) x(dstHours) x(dstMinutes) x(dstSeconds) \ |
|
x(startJ) x(startDayOfYear) \ |
|
x(startMonth) x(startWeekOfMonth) x(startDayOfWeek) \ |
|
x(startHours) x(startMinutes) x(startSeconds) \ |
|
x(endJ) x(endDayOfYear) \ |
|
x(endMonth) x(endWeekOfMonth) x(endDayOfWeek) \ |
|
x(endHours) x(endMinutes) x(endSeconds)] } { |
|
|
|
|
|
return [array get x] |
|
} |
|
|
|
return -code error\ |
|
-errorcode [list CLOCK badTimeZone $tz] \ |
|
"unable to parse time zone specification \"$tz\"" |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ProcessPosixTimeZone { z } { |
|
variable MINWIDE |
|
variable TZData |
|
|
|
|
|
|
|
set stdName [dict get $z stdName] |
|
if { [string index $stdName 0] eq {<} } { |
|
set stdName [string range $stdName 1 end-1] |
|
} |
|
if { [dict get $z stdSignum] eq {-} } { |
|
set stdSignum +1 |
|
} else { |
|
set stdSignum -1 |
|
} |
|
set stdHours [lindex [::scan [dict get $z stdHours] %d] 0] |
|
if { [dict get $z stdMinutes] ne {} } { |
|
set stdMinutes [lindex [::scan [dict get $z stdMinutes] %d] 0] |
|
} else { |
|
set stdMinutes 0 |
|
} |
|
if { [dict get $z stdSeconds] ne {} } { |
|
set stdSeconds [lindex [::scan [dict get $z stdSeconds] %d] 0] |
|
} else { |
|
set stdSeconds 0 |
|
} |
|
set stdOffset [expr { |
|
(($stdHours * 60 + $stdMinutes) * 60 + $stdSeconds) * $stdSignum |
|
}] |
|
set data [list [list $MINWIDE $stdOffset 0 $stdName]] |
|
|
|
|
|
|
|
set dstName [dict get $z dstName] |
|
if { $dstName eq {} } { |
|
return $data |
|
} |
|
if { [string index $dstName 0] eq {<} } { |
|
set dstName [string range $dstName 1 end-1] |
|
} |
|
|
|
|
|
|
|
if { [dict get $z dstSignum] eq {-} } { |
|
set dstSignum +1 |
|
} else { |
|
set dstSignum -1 |
|
} |
|
if { [dict get $z dstHours] eq {} } { |
|
set dstOffset [expr { 3600 + $stdOffset }] |
|
} else { |
|
set dstHours [lindex [::scan [dict get $z dstHours] %d] 0] |
|
if { [dict get $z dstMinutes] ne {} } { |
|
set dstMinutes [lindex [::scan [dict get $z dstMinutes] %d] 0] |
|
} else { |
|
set dstMinutes 0 |
|
} |
|
if { [dict get $z dstSeconds] ne {} } { |
|
set dstSeconds [lindex [::scan [dict get $z dstSeconds] %d] 0] |
|
} else { |
|
set dstSeconds 0 |
|
} |
|
set dstOffset [expr { |
|
(($dstHours*60 + $dstMinutes) * 60 + $dstSeconds) * $dstSignum |
|
}] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if { |
|
[dict get $z startDayOfYear] eq {} |
|
&& [dict get $z startMonth] eq {} |
|
} then { |
|
if {($stdSignum * $stdHours>=0) && ($stdSignum * $stdHours<=12)} { |
|
|
|
dict set z startWeekOfMonth 5 |
|
if {$stdHours>2} { |
|
dict set z startHours 2 |
|
} else { |
|
dict set z startHours [expr {$stdHours+1}] |
|
} |
|
} else { |
|
|
|
dict set z startWeekOfMonth 2 |
|
dict set z startHours 2 |
|
} |
|
dict set z startMonth 3 |
|
dict set z startDayOfWeek 0 |
|
dict set z startMinutes 0 |
|
dict set z startSeconds 0 |
|
} |
|
if { |
|
[dict get $z endDayOfYear] eq {} |
|
&& [dict get $z endMonth] eq {} |
|
} then { |
|
if {($stdSignum * $stdHours>=0) && ($stdSignum * $stdHours<=12)} { |
|
|
|
dict set z endMonth 10 |
|
dict set z endWeekOfMonth 5 |
|
if {$stdHours>2} { |
|
dict set z endHours 3 |
|
} else { |
|
dict set z endHours [expr {$stdHours+2}] |
|
} |
|
} else { |
|
|
|
dict set z endMonth 11 |
|
dict set z endWeekOfMonth 1 |
|
dict set z endHours 2 |
|
} |
|
dict set z endDayOfWeek 0 |
|
dict set z endMinutes 0 |
|
dict set z endSeconds 0 |
|
} |
|
|
|
|
|
|
|
for { set y 1916 } { $y < 2100 } { incr y } { |
|
set startTime [DeterminePosixDSTTime $z start $y] |
|
incr startTime [expr { - wide($stdOffset) }] |
|
set endTime [DeterminePosixDSTTime $z end $y] |
|
incr endTime [expr { - wide($dstOffset) }] |
|
if { $startTime < $endTime } { |
|
lappend data \ |
|
[list $startTime $dstOffset 1 $dstName] \ |
|
[list $endTime $stdOffset 0 $stdName] |
|
} else { |
|
lappend data \ |
|
[list $endTime $stdOffset 0 $stdName] \ |
|
[list $startTime $dstOffset 1 $dstName] |
|
} |
|
} |
|
|
|
return $data |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::DeterminePosixDSTTime { z bound y } { |
|
|
|
variable FEB_28 |
|
|
|
|
|
|
|
set date [dict create era CE year $y] |
|
set doy [dict get $z ${bound}DayOfYear] |
|
if { $doy ne {} } { |
|
|
|
|
|
|
|
if { [dict get $z ${bound}J] ne {} |
|
&& [IsGregorianLeapYear $y] |
|
&& ( $doy > $FEB_28 ) } { |
|
incr doy |
|
} |
|
dict set date dayOfYear $doy |
|
set date [GetJulianDayFromEraYearDay $date[set date {}] 2361222] |
|
} else { |
|
|
|
|
|
dict set date month [dict get $z ${bound}Month] |
|
dict set date dayOfWeek [dict get $z ${bound}DayOfWeek] |
|
set dowim [dict get $z ${bound}WeekOfMonth] |
|
if { $dowim >= 5 } { |
|
set dowim -1 |
|
} |
|
dict set date dayOfWeekInMonth $dowim |
|
set date [GetJulianDayFromEraYearMonthWeekDay $date[set date {}] 2361222] |
|
|
|
} |
|
|
|
set jd [dict get $date julianDay] |
|
set seconds [expr { |
|
wide($jd) * wide(86400) - wide(210866803200) |
|
}] |
|
|
|
set h [dict get $z ${bound}Hours] |
|
if { $h eq {} } { |
|
set h 2 |
|
} else { |
|
set h [lindex [::scan $h %d] 0] |
|
} |
|
set m [dict get $z ${bound}Minutes] |
|
if { $m eq {} } { |
|
set m 0 |
|
} else { |
|
set m [lindex [::scan $m %d] 0] |
|
} |
|
set s [dict get $z ${bound}Seconds] |
|
if { $s eq {} } { |
|
set s 0 |
|
} else { |
|
set s [lindex [::scan $s %d] 0] |
|
} |
|
set tod [expr { ( $h * 60 + $m ) * 60 + $s }] |
|
return [expr { $seconds + $tod }] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::GetLocaleEra { date etable } { |
|
set index [BSearch $etable [dict get $date localSeconds]] |
|
if { $index < 0} { |
|
dict set date localeEra \ |
|
[::format %02d [expr { [dict get $date year] / 100 }]] |
|
dict set date localeYear [expr { |
|
[dict get $date year] % 100 |
|
}] |
|
} else { |
|
dict set date localeEra [lindex $etable $index 1] |
|
dict set date localeYear [expr { |
|
[dict get $date year] - [lindex $etable $index 2] |
|
}] |
|
} |
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::GetJulianDayFromEraYearDay {date changeover} { |
|
|
|
|
|
switch -exact -- [dict get $date era] { |
|
BCE { |
|
set year [expr { 1 - [dict get $date year] }] |
|
} |
|
CE { |
|
set year [dict get $date year] |
|
} |
|
} |
|
set ym1 [expr { $year - 1 }] |
|
|
|
|
|
|
|
dict set date gregorian 1 |
|
set jd [expr { |
|
1721425 |
|
+ [dict get $date dayOfYear] |
|
+ ( 365 * $ym1 ) |
|
+ ( $ym1 / 4 ) |
|
- ( $ym1 / 100 ) |
|
+ ( $ym1 / 400 ) |
|
}] |
|
|
|
|
|
|
|
if { $jd < $changeover } { |
|
dict set date gregorian 0 |
|
set jd [expr { |
|
1721423 |
|
+ [dict get $date dayOfYear] |
|
+ ( 365 * $ym1 ) |
|
+ ( $ym1 / 4 ) |
|
}] |
|
} |
|
|
|
dict set date julianDay $jd |
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::GetJulianDayFromEraYearMonthWeekDay {date changeover} { |
|
|
|
|
|
|
|
|
|
set date2 $date |
|
set week [dict get $date dayOfWeekInMonth] |
|
if { $week >= 0 } { |
|
dict set date2 dayOfMonth 0 |
|
} else { |
|
dict incr date2 month |
|
dict set date2 dayOfMonth 7 |
|
} |
|
set date2 [GetJulianDayFromEraYearMonthDay $date2[set date2 {}] \ |
|
$changeover] |
|
set wd0 [WeekdayOnOrBefore [dict get $date dayOfWeek] \ |
|
[dict get $date2 julianDay]] |
|
dict set date julianDay [expr { $wd0 + 7 * $week }] |
|
return $date |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::IsGregorianLeapYear { date } { |
|
switch -exact -- [dict get $date era] { |
|
BCE { |
|
set year [expr { 1 - [dict get $date year]}] |
|
} |
|
CE { |
|
set year [dict get $date year] |
|
} |
|
} |
|
if { $year % 4 != 0 } { |
|
return 0 |
|
} elseif { ![dict get $date gregorian] } { |
|
return 1 |
|
} elseif { $year % 400 == 0 } { |
|
return 1 |
|
} elseif { $year % 100 == 0 } { |
|
return 0 |
|
} else { |
|
return 1 |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::WeekdayOnOrBefore { weekday j } { |
|
set k [expr { ( $weekday + 6 ) % 7 }] |
|
return [expr { $j - ( $j - $k ) % 7 }] |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::BSearch { list key } { |
|
if {[llength $list] == 0} { |
|
return -1 |
|
} |
|
if { $key < [lindex $list 0 0] } { |
|
return -1 |
|
} |
|
|
|
set l 0 |
|
set u [expr { [llength $list] - 1 }] |
|
|
|
while { $l < $u } { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
set m [expr { ( $l + $u + 1 ) / 2 }] |
|
if { $key >= [lindex $list $m 0] } { |
|
set l $m |
|
} else { |
|
set u [expr { $m - 1 }] |
|
} |
|
} |
|
|
|
return $l |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::add { clockval args } { |
|
if { [llength $args] % 2 != 0 } { |
|
set cmdName "clock add" |
|
return -code error \ |
|
-errorcode [list CLOCK wrongNumArgs] \ |
|
"wrong \# args: should be\ |
|
\"$cmdName clockval ?number units?...\ |
|
?-gmt boolean? ?-locale LOCALE? ?-timezone ZONE?\"" |
|
} |
|
if { [catch { expr {wide($clockval)} } result] } { |
|
return -code error $result |
|
} |
|
|
|
set offsets {} |
|
set gmt 0 |
|
set locale c |
|
set timezone [GetSystemTimeZone] |
|
|
|
foreach { a b } $args { |
|
if { [string is integer -strict $a] } { |
|
lappend offsets $a $b |
|
} else { |
|
switch -exact -- $a { |
|
-g - -gm - -gmt { |
|
set gmt $b |
|
} |
|
-l - -lo - -loc - -loca - -local - -locale { |
|
set locale [string tolower $b] |
|
} |
|
-t - -ti - -tim - -time - -timez - -timezo - -timezon - |
|
-timezone { |
|
set timezone $b |
|
} |
|
default { |
|
throw [list CLOCK badOption $a] \ |
|
"bad option \"$a\",\ |
|
must be -gmt, -locale or -timezone" |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
if { [info exists saw(-gmt)] && [info exists saw(-timezone)] } { |
|
return -code error \ |
|
-errorcode [list CLOCK gmtWithTimezone] \ |
|
"cannot use -gmt and -timezone in same call" |
|
} |
|
if { [catch { expr { wide($clockval) } } result] } { |
|
return -code error "expected integer but got \"$clockval\"" |
|
} |
|
if { ![string is boolean -strict $gmt] } { |
|
return -code error "expected boolean value but got \"$gmt\"" |
|
} elseif { $gmt } { |
|
set timezone :GMT |
|
} |
|
|
|
EnterLocale $locale |
|
|
|
set changeover [mc GREGORIAN_CHANGE_DATE] |
|
|
|
if {[catch {SetupTimeZone $timezone} retval opts]} { |
|
dict unset opts -errorinfo |
|
return -options $opts $retval |
|
} |
|
|
|
try { |
|
foreach { quantity unit } $offsets { |
|
switch -exact -- $unit { |
|
years - year { |
|
set clockval [AddMonths [expr { 12 * $quantity }] \ |
|
$clockval $timezone $changeover] |
|
} |
|
months - month { |
|
set clockval [AddMonths $quantity $clockval $timezone \ |
|
$changeover] |
|
} |
|
|
|
weeks - week { |
|
set clockval [AddDays [expr { 7 * $quantity }] \ |
|
$clockval $timezone $changeover] |
|
} |
|
days - day { |
|
set clockval [AddDays $quantity $clockval $timezone \ |
|
$changeover] |
|
} |
|
|
|
hours - hour { |
|
set clockval [expr { 3600 * $quantity + $clockval }] |
|
} |
|
minutes - minute { |
|
set clockval [expr { 60 * $quantity + $clockval }] |
|
} |
|
seconds - second { |
|
set clockval [expr { $quantity + $clockval }] |
|
} |
|
|
|
default { |
|
throw [list CLOCK badUnit $unit] \ |
|
"unknown unit \"$unit\", must be \ |
|
years, months, weeks, days, hours, minutes or seconds" |
|
} |
|
} |
|
} |
|
return $clockval |
|
} trap CLOCK {result opts} { |
|
|
|
dict unset opts -errorinfo |
|
return -options $opts $result |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::AddMonths { months clockval timezone changeover } { |
|
variable DaysInRomanMonthInCommonYear |
|
variable DaysInRomanMonthInLeapYear |
|
variable TZData |
|
|
|
|
|
|
|
set date [GetDateFields $clockval $TZData($timezone) $changeover] |
|
dict set date secondOfDay [expr { |
|
[dict get $date localSeconds] % 86400 |
|
}] |
|
dict set date tzName $timezone |
|
|
|
|
|
|
|
set m [dict get $date month] |
|
incr m $months |
|
incr m -1 |
|
set delta [expr { $m / 12 }] |
|
set mm [expr { $m % 12 }] |
|
dict set date month [expr { $mm + 1 }] |
|
dict incr date year $delta |
|
|
|
|
|
|
|
if { [IsGregorianLeapYear $date] } { |
|
set hath [lindex $DaysInRomanMonthInLeapYear $mm] |
|
} else { |
|
set hath [lindex $DaysInRomanMonthInCommonYear $mm] |
|
} |
|
if { [dict get $date dayOfMonth] > $hath } { |
|
dict set date dayOfMonth $hath |
|
} |
|
|
|
|
|
|
|
set date [GetJulianDayFromEraYearMonthDay \ |
|
$date[set date {}]\ |
|
$changeover] |
|
dict set date localSeconds [expr { |
|
-210866803200 |
|
+ ( 86400 * wide([dict get $date julianDay]) ) |
|
+ [dict get $date secondOfDay] |
|
}] |
|
set date [ConvertLocalToUTC $date[set date {}] $TZData($timezone) \ |
|
$changeover] |
|
|
|
return [dict get $date seconds] |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::AddDays { days clockval timezone changeover } { |
|
variable TZData |
|
|
|
|
|
|
|
set date [GetDateFields $clockval $TZData($timezone) $changeover] |
|
dict set date secondOfDay [expr { |
|
[dict get $date localSeconds] % 86400 |
|
}] |
|
dict set date tzName $timezone |
|
|
|
|
|
|
|
dict incr date julianDay $days |
|
|
|
|
|
|
|
dict set date localSeconds [expr { |
|
-210866803200 |
|
+ ( 86400 * wide([dict get $date julianDay]) ) |
|
+ [dict get $date secondOfDay] |
|
}] |
|
set date [ConvertLocalToUTC $date[set date {}] $TZData($timezone) \ |
|
$changeover] |
|
|
|
return [dict get $date seconds] |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ChangeCurrentLocale {args} { |
|
variable FormatProc |
|
variable LocaleNumeralCache |
|
variable CachedSystemTimeZone |
|
variable TimeZoneBad |
|
|
|
foreach p [info procs [namespace current]::scanproc'*'current] { |
|
rename $p {} |
|
} |
|
foreach p [info procs [namespace current]::formatproc'*'current] { |
|
rename $p {} |
|
} |
|
|
|
catch {array unset FormatProc *'current} |
|
set LocaleNumeralCache {} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::clock::ClearCaches {} { |
|
variable FormatProc |
|
variable LocaleNumeralCache |
|
variable CachedSystemTimeZone |
|
variable TimeZoneBad |
|
|
|
foreach p [info procs [namespace current]::scanproc'*] { |
|
rename $p {} |
|
} |
|
foreach p [info procs [namespace current]::formatproc'*] { |
|
rename $p {} |
|
} |
|
|
|
catch {unset FormatProc} |
|
set LocaleNumeralCache {} |
|
catch {unset CachedSystemTimeZone} |
|
set TimeZoneBad {} |
|
InitTZData |
|
} |
|
|