!C99Shell v. 2.0 [PHP 7 Update] [25.02.2019]!

Software: Apache/2.2.16 (Debian). PHP/5.3.3-7+squeeze19 

uname -a: Linux mail.tri-specialutilitydistrict.com 2.6.32-5-amd64 #1 SMP Tue May 13 16:34:35 UTC
2014 x86_64
 

uid=33(www-data) gid=33(www-data) groups=33(www-data) 

Safe-mode: OFF (not secure)

/usr/share/tcltk/tcl8.5/   drwxr-xr-x
Free 130.06 GB of 142.11 GB (91.52%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     clock.tcl (127.01 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#----------------------------------------------------------------------
#
# clock.tcl --
#
#    This file implements the portions of the [clock] ensemble that
#    are coded in Tcl.  Refer to the users' manual to see the description
#    of the [clock] command and its subcommands.
#
#
#----------------------------------------------------------------------
#
# Copyright (c) 2004,2005,2006,2007 by Kevin B. Kenny
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: clock.tcl,v 1.47.2.9 2009/10/29 01:17:03 kennykb Exp $
#
#----------------------------------------------------------------------

# We must have message catalogs that support the root locale, and
# we need access to the Registry on Windows systems.

uplevel \#0 {
    package require msgcat 1.4
    if { $::tcl_platform(platform) eq {windows} } {
    if { [catch { package require registry 1.1 }] } {
        namespace eval ::tcl::clock [list variable NoRegistry {}]
    }
    }
}

# Put the library directory into the namespace for the ensemble
# so that the library code can find message catalogs and time zone
# definition files.

namespace eval ::tcl::clock \
    [list variable LibDir [file dirname [info script]]]

#----------------------------------------------------------------------
#
# clock --
#
#    Manipulate times.
#
# The 'clock' command manipulates time.  Refer to the user documentation
# for the available subcommands and what they do.
#
#----------------------------------------------------------------------    

namespace eval ::tcl::clock {

    # Export the subcommands

    namespace export format
    namespace export clicks
    namespace export microseconds
    namespace export milliseconds
    namespace export scan
    namespace export seconds
    namespace export add

    # Import the message catalog commands that we use.

    namespace import ::msgcat::mcload
    namespace import ::msgcat::mclocale

}

#----------------------------------------------------------------------
#
# ::tcl::clock::Initialize --
#
#    Finish initializing the 'clock' subsystem
#
# Results:
#    None.
#
# Side effects:
#    Namespace variable in the 'clock' subsystem are initialized.
#
# The '::tcl::clock::Initialize' procedure initializes the namespace
# variables and root locale message catalog for the 'clock' subsystem.
# It is broken into a procedure rather than simply evaluated as a script
# so that it will be able to use local variables, avoiding the dangers
# of 'creative writing' as in Bug 1185933.
#
#----------------------------------------------------------------------

proc ::tcl::clock::Initialize {} {

    rename ::tcl::clock::Initialize {}

    variable LibDir

    # Define the Greenwich time zone

    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

    # Define the message catalog for the root locale.

    ::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}
    }

    # Define a few Gregorian change dates for other locales.  In most cases
    # the change date follows a language, because a nation's colonies changed
    # at the same time as the nation itself.  In many cases, different
    # national boundaries existed; the dominating rule is to follow the
    # nation's capital.

    # Italy, Spain, Portugal, Poland

    ::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

    # France, Austria

    ::msgcat::mcset fr GREGORIAN_CHANGE_DATE 2299227

    # For Belgium, we follow Southern Netherlands; Liege Diocese
    # changed several weeks later.

    ::msgcat::mcset fr_BE GREGORIAN_CHANGE_DATE 2299238
    ::msgcat::mcset nl_BE GREGORIAN_CHANGE_DATE 2299238

    # Austria

    ::msgcat::mcset de_AT GREGORIAN_CHANGE_DATE 2299527

    # Hungary

    ::msgcat::mcset hu GREGORIAN_CHANGE_DATE 2301004

    # Germany, Norway, Denmark (Catholic Germany changed earlier)

    ::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

    # Holland (Brabant, Gelderland, Flanders, Friesland, etc. changed
    # at various times)

    ::msgcat::mcset nl GREGORIAN_CHANGE_DATE 2342165

    # Protestant Switzerland (Catholic cantons changed earlier)

    ::msgcat::mcset fr_CH GREGORIAN_CHANGE_DATE 2361342
    ::msgcat::mcset it_CH GREGORIAN_CHANGE_DATE 2361342
    ::msgcat::mcset de_CH GREGORIAN_CHANGE_DATE 2361342

    # English speaking countries

    ::msgcat::mcset en GREGORIAN_CHANGE_DATE 2361222

    # Sweden (had several changes onto and off of the Gregorian calendar)

    ::msgcat::mcset sv GREGORIAN_CHANGE_DATE 2361390

    # Russia

    ::msgcat::mcset ru GREGORIAN_CHANGE_DATE 2421639

    # Romania (Transylvania changed earler - perhaps de_RO should show
    # the earlier date?)

    ::msgcat::mcset ro GREGORIAN_CHANGE_DATE 2422063

    # Greece

    ::msgcat::mcset el GREGORIAN_CHANGE_DATE 2423480
    
    #------------------------------------------------------------------
    #
    #                CONSTANTS
    #
    #------------------------------------------------------------------

    # Paths at which binary time zone data for the Olson libraries
    # are known to reside on various operating systems

    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
    }
    }

    # Define the directories for time zone data and message catalogs.

    variable DataDir [file join $LibDir tzdata]
    variable MsgDir [file join $LibDir msgs]

    # Number of days in the months, in common years and leap years.

    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]
    }

    # Another epoch (Hi, Jeff!)

    variable Roddenberry 1946

    # Integer ranges

    variable MINWIDE -9223372036854775808
    variable MAXWIDE 9223372036854775807

    # Day before Leap Day

    variable FEB_28           58

    # 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 to specify $::env(TCL_TZ) rather than simply depending
    # on the system time zone.

    # The keys are long lists of values obtained from the time zone
    # information in the Registry.  In order, the list elements are:
    #     Bias StandardBias DaylightBias
    #   StandardDate.wYear StandardDate.wMonth StandardDate.wDayOfWeek
    #   StandardDate.wDay StandardDate.wHour StandardDate.wMinute
    #   StandardDate.wSecond StandardDate.wMilliseconds
    #   DaylightDate.wYear DaylightDate.wMonth DaylightDate.wDayOfWeek
    #   DaylightDate.wDay DaylightDate.wHour DaylightDate.wMinute
    #   DaylightDate.wSecond DaylightDate.wMilliseconds
    # The values are the names of time zones where those rules apply.
    # There is considerable ambiguity in certain zones; an attempt has
    # been made to make a reasonable guess, but this table needs to be
    # taken with a grain of salt.

    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/Brasilia
        {-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
    }]

    # Groups of fields that specify the date, priorities, and 
    # code bursts that determine Julian Day Number given those groups.
    # The code in [clock scan] will choose the highest priority
    # (lowest numbered) set of fields that determines the date.

    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]
    }
    }

    # Groups of fields that specify time of day, priorities,
    # and code that processes them

    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
    }
    }

    # Legacy time zones, used primarily for parsing RFC822 dates.

    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 \
    ]

    # Caches

    variable LocaleNumeralCache {};    # Dictionary whose keys are locale
                    # names and whose values are pairs
                    # comprising regexes matching numerals
                    # in the given locales and dictionaries
                    # mapping the numerals to their numeric
                    # values.
    variable McLoaded {};        # Dictionary whose keys are locales
                    # in which [mcload] has been executed
                    # and whose values are second-level
                        # dictionaries indexed by message
                        # name and giving message text.
    # variable CachedSystemTimeZone;    # If 'CachedSystemTimeZone' exists,
                    # it contains the value of the
                    # system time zone, as determined from
                    # the environment.
    variable TimeZoneBad {};            # Dictionary whose keys are time zone
                        # names and whose values are 1 if
                    # the time zone is unknown and 0
                        # if it is known.
    variable TZData;            # Array whose keys are time zone names
                    # and whose values are lists of quads
                    # comprising start time, UTC offset,
                    # Daylight Saving Time indicator, and
                    # time zone abbreviation.
    variable FormatProc;        # Array mapping format group
                    # and locale to the name of a procedure
                    # that renders the given format
}
::tcl::clock::Initialize

#----------------------------------------------------------------------
#
# clock format --
#
#    Formats a count of seconds since the Posix Epoch as a time
#    of day.
#
# The 'clock format' command formats times of day for output.
# Refer to the user documentation to see what it does.
#
#----------------------------------------------------------------------

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]

    # Get the data for time changes in the given zone
    
    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
    }
    }
    
    # Build a procedure to format the result. Cache the built procedure's
    # name in the 'FormatProc' array to avoid losing its internal
    # representation, which contains the name resolution.
    
    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]

}

#----------------------------------------------------------------------
#
# ParseClockFormatFormat --
#
#    Builds and caches a procedure that formats a time value.
#
# Parameters:
#    format -- Format string to use
#    locale -- Locale in which the format string is to be interpreted
#
# Results:
#    Returns the name of the newly-built procedure.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ParseClockFormatFormat {procName format locale} {

    if {[namespace which $procName] ne {}} {
    return $procName
    }

    # Map away the locale-dependent composite format groups
    
    EnterLocale $locale oldLocale

    # Change locale if a fresh locale has been given on the command line.

    set status [catch {

    ParseClockFormatFormat2 $format $locale $procName

    } result opts]

    # Restore the locale

    if { [info exists oldLocale] } {
    mclocale $oldLocale
    }

    # Return either the error or the proc name

    if { $status == 1 } {
    if { [lindex [dict get $opts -errorcode] 0] eq {clock} } {
        return -code error $result
    } else {
        return -options $opts $result
    }
    } else {
    return $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
                    # alternative era
            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
                    # week number
            append formatString %02d
            append substituents \
                { [expr { [dict get $date iso8601Year] % 100 }]}
            }
            G {            # Four-digit year relative to ISO8601
                    # week number
            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
                    # alternative numerals
            set state percentO
            if {!$didLocaleNumerals} {
                append preFormatCode \
                [list set localeNumerals \
                     [mc LOCALE_NUMERALS]] \n
                set didLocaleNumerals 1
            }
            }
            p {            # Localized 'AM' or 'PM' indicator
                    # converted to uppercase
            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 
            # leading zero
            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
                    # first Sunday of the year is the
                    # first day of week 01
            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,
                    # 6-Saturday)
            append formatString %1d
            append substituents \
                { [expr { [dict get $date dayOfWeek] % 7 }]}
            }
            W {            # Week of the year (00-53). The first
                    # Monday of the year is the first day
                    # of week 01.
            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
                    # east (+) or west (-) of Greenwich
            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 
            # numerals
            append formatString %s
            append substituents \
                { [lindex $localeNumerals \
                   [dict get $date dayOfMonth]]}
            }
            H - k {        # Hour of the day in alternative
                    # numerals
            append formatString %s
            append substituents \
                { [lindex $localeNumerals \
                   [expr { [dict get $date localSeconds] 
                       / 3600
                       % 24 }]]}
            }
            I - l {        # Hour (12-11) AM/PM in alternative
                    # numerals
            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
                    # numerals
            append formatString %s
            append substituents \
                { [lindex $localeNumerals \
                   [expr { [dict get $date localSeconds] 
                       / 60
                       % 60 }]]}
            }
            S {            # Second of the minute in alternative
                    # numerals
            append formatString %s
            append substituents \
                { [lindex $localeNumerals \
                   [expr { [dict get $date localSeconds] 
                       % 60 }]]}
            }
            u {            # Day of the week (Monday=1,Sunday=7)
                    # in alternative numerals
            append formatString %s
            append substituents \
                { [lindex $localeNumerals \
                   [dict get $date dayOfWeek]]}
            }
            w {            # Day of the week (Sunday=0,Saturday=6)
                    # in alternative numerals
            append formatString %s
            append substituents \
                { [lindex $localeNumerals \
                   [expr { [dict get $date dayOfWeek] % 7 }]]}
            }
            y {            # Year of the century in alternative
                    # numerals
            append formatString %s
            append substituents \
                { [lindex $localeNumerals \
                   [expr { [dict get $date year] % 100 }]]}
            }
            default {    # Unknown format group
            append formatString %%O $char
            }
        }
        }
    }
    }
    
    # Clean up any improperly terminated groups
    
    switch -exact -- $state {
    percent {
        append formatString %%
    }
    percentE {
        append retval %%E
    }
    percentO {
        append retval %%O
    }
    }

    proc $procName {clockval timezone} "
        $preFormatCode
        return \[::format [list $formatString] $substituents\]
    "

    #    puts [list $procName [info args $procName] [info body $procName]]

    return $procName
}

#----------------------------------------------------------------------
#
# clock scan --
#
#    Inputs a count of seconds since the Posix Epoch as a time
#    of day.
#
# The 'clock format' command scans times of day on input.
# Refer to the user documentation to see what it does.
#
#----------------------------------------------------------------------

proc ::tcl::clock::scan { args } {

    set format {}

    # Check the count of args

    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 defaults

    set base [clock seconds]
    set string [lindex $args 0]
    set format {}
    set gmt 0
    set locale c
    set timezone [GetSystemTimeZone]

    # Pick up command line options.

    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 badSwitch $flag] \
            "bad switch \"$flag\",\
                     must be -base, -format, -gmt, -locale or -timezone"
        }
    }
    }

    # Check options for validity

    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 $gmt] } {
    return -code error \
        "expected boolean value but got \"$gmt\""
    } else {
    if { $gmt } {
        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 oldLocale

    set status [catch {

    # Map away the locale-dependent composite format groups

    set scanner [ParseClockScanFormat $format $locale]
    $scanner $string $base $timezone

    } result opts]

    # Restore the locale

    if { [info exists oldLocale] } {
    mclocale $oldLocale
    }

    if { $status == 1 } {
    if { [lindex [dict get $opts -errorcode] 0] eq {clock} } {
        return -code error $result
    } else {
        return -options $opts $result
    }
    } else {
    return $result
    }

}

#----------------------------------------------------------------------
#
# 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::FreeScan { string base timezone locale } {

    variable TZData

    # Get the data for time changes in the given zone
    
    if {[catch {SetupTimeZone $timezone} 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.

    set status [catch {
    Oldscan $string \
        [dict get $date year] \
        [dict get $date month] \
        [dict get $date dayOfMonth]
    } result]
    if { $status != 0 } {
    return -code error "unable to convert date-time string \"$string\": $result"
    }

    lassign $result parseDate parseTime parseZone parseRel \
    parseWeekday parseOrdinalMonth

    # 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 } {
        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 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]
#
# Parameters:
#    formatString - The format being parsed
#    locale - The current locale
#
# Results:
#    Constructs and returns a procedure that accepts the
#    string being scanned, the base time, and the time zone.  
#    The procedure will either return the scanned time or
#    else throw an error that should be rethrown to the caller
#    of [clock scan]
#
# Side effects:
#    The given procedure is defined in the ::tcl::clock
#    namespace.  Scan procedures are not deleted once installed.
#
# Why do we parse dates by defining a procedure to parse them?
# The reason is that by doing so, we have one convenient place to
# cache all the information: the regular expressions that match the
# patterns (which will be compiled), the code that assembles the
# date information, everything lands in one place.  In this way,
# when a given format is reused at run time, all the information
# of how to apply it is available in a single place.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ParseClockScanFormat {formatString locale} {

    # Check whether the format has been parsed previously, and return
    # the existing recognizer if it has.

    set procName scanproc'$formatString'$locale
    set procName [namespace current]::[string map {: {\:} \\ {\\}} $procName]
    if { [namespace which $procName] != {} } {
    return $procName
    }

    variable DateParseActions
    variable TimeParseActions

    # Localize the %x, %X, etc. groups

    set formatString [LocalizeFormat $locale $formatString]

    # Condense whitespace

    regsub -all {[[:space:]]+} $formatString { } formatString

    # Walk through the groups of the format string.  In this loop, we
    # accumulate:
    #    - a regular expression that matches the string,
    #   - the count of capturing brackets in the regexp
    #   - a set of code that post-processes the fields captured by the regexp,
    #   - a dictionary whose keys are the names of fields that are present
    #     in the format string.

    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
            # This next case is insanely difficult,
            # because it's problematic to determine
            # whether the field is actually within
            # the range of a wide integer.
            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
                    # 1=Mon, 6=Sat
            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 the year is the
                    # first day of week 01. No scan rule
                    # uses this group.
            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
                    # Monday of the year is the first day
                    # of week 01. No scan rule uses this
                    # group.
            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 {}
        }
    }
    }

    # Clean up any unfinished format groups

    append re $state \\s*\$

    # Build the procedure

    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

    # Get time zone if needed

    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
    }
    }

    # Add code that gets Julian Day Number from the fields.

    append procBody [MakeParseCodeFromFields $fieldSet $DateParseActions]

    # Get time of day

    append procBody [MakeParseCodeFromFields $fieldSet $TimeParseActions]

    # Assemble seconds, and convert local nominal time to UTC.

    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]
    }
    }

    # Return result

    append procBody {return [dict get $date seconds]} \n

    proc $procName { string baseTime timeZone } $procBody

    # puts [list proc $procName [list string baseTime timeZone] $procBody]

    return $procName
}
    
#----------------------------------------------------------------------
#
# LocaleNumeralMatcher --
#
#    Composes a regexp that captures the numerals in the given
#    locale, and a dictionary to map them to conventional numerals.
#
# Parameters:
#    locale - Name of the current locale
#
# Results:
#    Returns a two-element list comprising the regexp and the
#    dictionary.
#
# Side effects:
#    Caches the result.
#
#----------------------------------------------------------------------

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]
}
    


#----------------------------------------------------------------------
#
# UniquePrefixRegexp --
#
#    Composes a regexp that performs unique-prefix matching.  The
#    RE matches one of a supplied set of strings, or any unique
#    prefix thereof.
#
# Parameters:
#    data - List of alternating match-strings and values.
#           Match-strings with distinct values are considered
#           distinct.
#
# Results:
#    Returns a two-element list.  The first is a regexp that
#    matches any unique prefix of any of the strings.  The second
#    is a dictionary whose keys are match values from the regexp
#    and whose values are the corresponding values from 'data'.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::UniquePrefixRegexp { data } {

    # The 'successors' dictionary will contain, for each string that
    # is a prefix of any key, all characters that may follow that
    # prefix.  The 'prefixMapping' dictionary will have keys that
    # are prefixes of keys and values that correspond to the keys.

    set prefixMapping [dict create]
    set successors [dict create {} {}]

    # Walk the key-value pairs

    foreach { key value } $data {

    # Construct all prefixes of the key; 

    set prefix {}
    foreach char [split $key {}] {
        set oldPrefix $prefix
        dict set successors $oldPrefix $char {}
        append prefix $char

        # Put the prefixes in the 'prefixMapping' and 'successors'
        # dictionaries

        dict lappend prefixMapping $prefix $value
        if { ![dict exists $successors $prefix] } {
        dict set successors $prefix {}
        }
    }
    }

    # Identify those prefixes that designate unique values, and
    # those that are the full keys

    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
    }

    # Construct the re.

    return [list \
        [MakeUniquePrefixRegexp $successors $uniquePrefixMapping {}] \
        $uniquePrefixMapping]
}

#----------------------------------------------------------------------
#
# MakeUniquePrefixRegexp --
#
#    Service procedure for 'UniquePrefixRegexp' that constructs
#    a regular expresison that matches the unique prefixes.
#
# Parameters:
#    successors - Dictionary whose keys are all prefixes
#             of keys passed to 'UniquePrefixRegexp' and whose
#             values are dictionaries whose keys are the characters
#             that may follow those prefixes.
#    uniquePrefixMapping - Dictionary whose keys are the unique
#                  prefixes and whose values are not examined.
#    prefixString - Current prefix being processed.
#
# Results:
#    Returns a constructed regular expression that matches the set
#    of unique prefixes beginning with the 'prefixString'.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::MakeUniquePrefixRegexp { successors 
                      uniquePrefixMapping
                      prefixString } {

    # Get the characters that may follow the current prefix string

    set schars [lsort -ascii [dict keys [dict get $successors $prefixString]]]
    if { [llength $schars] == 0 } {
    return {}
    }

    # If there is more than one successor character, or if the current
    # prefix is a unique prefix, surround the generated re with non-capturing
    # parentheses.

    set re {}
    if { [dict exists $uniquePrefixMapping $prefixString]
     || [llength $schars] > 1 } {
    append re "(?:"
    }

    # Generate a regexp that matches the successors.

    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 the current prefix is a unique prefix, make all following text
    # optional. Otherwise, if there is more than one successor character,
    # close the non-capturing parentheses.

    if { [dict exists $uniquePrefixMapping $prefixString] } {
    append re ")?"
    }  elseif { [llength $schars] > 1 } {
    append re ")"
    }

    return $re
}

#----------------------------------------------------------------------
#
# MakeParseCodeFromFields --
#
#    Composes Tcl code to extract the Julian Day Number from a
#    dictionary containing date fields.
#
# Parameters:
#    dateFields -- Dictionary whose keys are fields of the date,
#                  and whose values are the rightmost positions
#              at which those fields appear.
#    parseActions -- List of triples: field set, priority, and
#            code to emit.  Smaller priorities are better, and
#            the list must be in ascending order by priority
#
# Results:
#    Returns a burst of code that extracts the day number from the
#    given date.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

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 we've found an answer that's better than any that follow,
    # quit now.

    if { $prio > $currPrio } {
        break
    }

    # Accumulate the field positions that are used in the current
    # field grouping.

    set fieldPos [list]
    set ok true
    foreach field $fieldSet {
        if { ! [dict exists $dateFields $field] } {
        set ok 0
        break
        }
        lappend fieldPos [dict get $dateFields $field]
    }

    # Quit if we don't have a complete set of fields
    if { !$ok } {
        continue
    }

    # Determine whether the current answer is better than the last.

    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 } {
            break
        }
        if { $newPos < $currPos } {
            set ok 0
            break
        }
        }
    }
    if { !$ok } {
        continue
    }

    # Remember the best possibility for extracting date information

    set currPrio $prio
    set currFieldPos $fPos
    set currCodeBurst $parseAction
        
    }

    return $currCodeBurst

}

#----------------------------------------------------------------------
#
# EnterLocale --
#
#    Switch [mclocale] to a given locale if necessary
#
# Parameters:
#    locale -- Desired locale
#    oldLocaleVar -- Name of a variable in caller's scope that
#                tracks the previous locale name.
#
# Results:
#    Returns the locale that was previously current.
#
# Side effects:
#    Does [mclocale].  If necessary, uses [mcload] to load the
#    designated locale's files, and tracks that it has done so
#    in the 'McLoaded' variable.
#
#----------------------------------------------------------------------

proc ::tcl::clock::EnterLocale { locale oldLocaleVar } {

    upvar 1 $oldLocaleVar oldLocale

    variable MsgDir
    variable McLoaded

    set oldLocale [mclocale]
    if { $locale eq {system} } {

    if { $::tcl_platform(platform) ne {windows} } {

        # On a non-windows platform, the 'system' locale is
        # the same as the 'current' locale

        set locale current
    } else {

        # On a windows platform, the 'system' locale is
        # adapted from the 'current' locale by applying the
        # date and time formats from the Control Panel.
        # First, load the 'current' locale if it's not yet loaded

        if {![dict exists $McLoaded $oldLocale] } {
        mcload $MsgDir
        dict set McLoaded $oldLocale {}
        }

        # Make a new locale string for the system locale, and
        # get the Control Panel information

        set locale ${oldLocale}_windows
        if { ![dict exists $McLoaded $locale] } {
        LoadWindowsDateTimeFormats $locale
        dict set McLoaded $locale {}
        }
    }
    }
    if { $locale eq {current}} {
    set locale $oldLocale
    unset oldLocale
    } elseif { $locale eq $oldLocale } {
    unset oldLocale
    } else {
    mclocale $locale
    }
    if { ![dict exists $McLoaded $locale] } {
    mcload $MsgDir
    dict set McLoaded $locale {}
    }

}    

#----------------------------------------------------------------------
#
# LoadWindowsDateTimeFormats --
#
#    Load the date/time formats from the Control Panel in Windows
#    and convert them so that they're usable by Tcl.
#
# Parameters:
#    locale - Name of the locale in whose message catalog
#             the converted formats are to be stored.
#
# Results:
#    None.
#
# Side effects:
#    Updates the given message catalog with the locale strings.
#
# Presumes that on entry, [mclocale] is set to the current locale,
# so that default strings can be obtained if the Registry query
# fails.
#
#----------------------------------------------------------------------

proc ::tcl::clock::LoadWindowsDateTimeFormats { locale } {

    # Bail out if we can't find the Registry

    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

}

#----------------------------------------------------------------------
#
# LocalizeFormat --
#
#    Map away locale-dependent format groups in a clock format.
#
# Parameters:
#    locale -- Current [mclocale] locale, supplied to avoid
#          an extra call
#    format -- Format supplied to [clock scan] or [clock format]
#
# Results:
#    Returns the string with locale-dependent composite format
#    groups substituted out.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::LocalizeFormat { locale format } {

    variable McLoaded

    if { [dict exists $McLoaded $locale FORMAT $format] } {
    return [dict get $McLoaded $locale FORMAT $format]
    }
    set inFormat $format

    # Handle locale-dependent format groups by mapping them out of the format
    # string.  Note that the order of the [string map] operations is
    # significant because later formats can refer to later ones; for example
    # %c can refer to %X, which in turn can refer to %T.
    
    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]
                       
    dict set McLoaded $locale FORMAT $inFormat $format
    return $format
}

#----------------------------------------------------------------------
#
# FormatNumericTimeZone --
#
#    Formats a time zone as +hhmmss
#
# Parameters:
#    z - Time zone in seconds east of Greenwich
#
# Results:
#    Returns the time zone formatted in a numeric form
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

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

}

#----------------------------------------------------------------------
#
# FormatStarDate --
#
#    Formats a date as a StarDate.
#
# Parameters:
#    date - Dictionary containing 'year', 'dayOfYear', and
#           'localSeconds' fields.
#
# Results:
#    Returns the given date formatted as a StarDate.
#
# Side effects:
#    None.
#
# Jeff Hobbs put this in to support an atrocious pun about Tcl being
# "Enterprise ready."  Now we're stuck with it.
#
#----------------------------------------------------------------------

proc ::tcl::clock::FormatStarDate { date } {

    variable Roddenberry

    # Get day of year, zero based

    set doy [expr { [dict get $date dayOfYear] - 1 }]

    # Determine whether the year is a leap year

    set lp [IsGregorianLeapYear $date]

    # Convert day of year to a fractional year

    if { $lp } {
    set fractYear [expr { 1000 * $doy / 366 }]
    } else {
    set fractYear [expr { 1000 * $doy / 365 }]
    }

    # Put together the StarDate

    return [::format "Stardate %02d%03d.%1d" \
        [expr { [dict get $date year] - $Roddenberry }] \
        $fractYear \
        [expr { [dict get $date localSeconds] % 86400
            / ( 86400 / 10 ) }]]
}

#----------------------------------------------------------------------
#
# ParseStarDate --
#
#    Parses a StarDate
#
# Parameters:
#    year - Year from the Roddenberry epoch
#    fractYear - Fraction of a year specifiying the day of year.
#    fractDay - Fraction of a day
#
# Results:
#    Returns a count of seconds from the Posix epoch.
#
# Side effects:
#    None.
#
# Jeff Hobbs put this in to support an atrocious pun about Tcl being
# "Enterprise ready."  Now we're stuck with it.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ParseStarDate { year fractYear fractDay } {

    variable Roddenberry

    # Build a tentative date from year and fraction.

    set date [dict create \
          gregorian 1 \
          era CE \
          year [expr { $year + $Roddenberry }] \
          dayOfYear [expr { $fractYear * 365 / 1000 + 1 }]]
    set date [GetJulianDayFromGregorianEraYearDay $date[set date {}]]

    # Determine whether the given year is a leap year

    set lp [IsGregorianLeapYear $date]

    # Reconvert the fractional year according to whether the given
    # year is a leap year

    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 }]

}

#----------------------------------------------------------------------
#
# ScanWide --
#
#    Scans a wide integer from an input
#
# Parameters:
#    str - String containing a decimal wide integer
#
# Results:
#    Returns the string as a pure wide integer.  Throws an error if
#    the string is misformatted or out of range.
#
#----------------------------------------------------------------------

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
}

#----------------------------------------------------------------------
#
# InterpretTwoDigitYear --
#
#    Given a date that contains only the year of the century,
#    determines the target value of a two-digit year.
#
# Parameters:
#    date - Dictionary containing fields of the date.
#    baseTime - Base time relative to which the date is expressed.
#    twoDigitField - Name of the field that stores the two-digit year.
#            Default is 'yearOfCentury'
#    fourDigitField - Name of the field that will receive the four-digit
#                     year.  Default is 'year'
#
# Results:
#    Returns the dictionary augmented with the four-digit year, stored in
#    the given key.
#
# Side effects:
#    None.
#
# The current rule for interpreting a two-digit year is that the year
# shall be between 1937 and 2037, thus staying within the range of a
# 32-bit signed value for time.  This rule may change to a sliding
# window in future versions, so the 'baseTime' parameter (which is
# currently ignored) is provided in the procedure signature.
#
#----------------------------------------------------------------------

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

}

#----------------------------------------------------------------------
#
# AssignBaseYear --
#
#    Places the number of the current year into a dictionary.
#
# Parameters:
#    date - Dictionary value to update
#    baseTime - Base time from which to extract the year, expressed
#           in seconds from the Posix epoch
#    timezone - the time zone in which the date is being scanned
#    changeover - the Julian Day on which the Gregorian calendar
#             was adopted in the target locale.
#
# Results:
#    Returns the dictionary with the current year assigned.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AssignBaseYear { date baseTime timezone changeover } {

    variable TZData

    # Find the Julian Day Number corresponding to the base time, and
    # find the Gregorian year corresponding to that Julian Day.

    set date2 [GetDateFields $baseTime $TZData($timezone) $changeover]

    # Store the converted year

    dict set date era [dict get $date2 era]
    dict set date year [dict get $date2 year]

    return $date

}

#----------------------------------------------------------------------
#
# AssignBaseIso8601Year --
#
#    Determines the base year in the ISO8601 fiscal calendar.
#
# Parameters:
#    date - Dictionary containing the fields of the date that
#           is to be augmented with the base year.
#    baseTime - Base time expressed in seconds from the Posix epoch.
#    timeZone - Target time zone
#    changeover - Julian Day of adoption of the Gregorian calendar in
#             the target locale.
#
# Results:
#    Returns the given date with "iso8601Year" set to the
#    base year.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AssignBaseIso8601Year {date baseTime timeZone changeover} {

    variable TZData

    # Find the Julian Day Number corresponding to the base time

    set date2 [GetDateFields $baseTime $TZData($timeZone) $changeover]

    # Calculate the ISO8601 date and transfer the year

    dict set date era CE
    dict set date iso8601Year [dict get $date2 iso8601Year]
    return $date
}

#----------------------------------------------------------------------
#
# AssignBaseMonth --
#
#    Places the number of the current year and month into a 
#    dictionary.
#
# Parameters:
#    date - Dictionary value to update
#    baseTime - Time from which the year and month are to be
#               obtained, expressed in seconds from the Posix epoch.
#    timezone - Name of the desired time zone
#    changeover - Julian Day on which the Gregorian calendar was adopted.
#
# Results:
#    Returns the dictionary with the base year and month assigned.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AssignBaseMonth {date baseTime timezone changeover} {

    variable TZData

    # Find the year and month corresponding to the base time

    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

}

#----------------------------------------------------------------------
#
# AssignBaseWeek --
#
#    Determines the base year and week in the ISO8601 fiscal calendar.
#
# Parameters:
#    date - Dictionary containing the fields of the date that
#           is to be augmented with the base year and week.
#    baseTime - Base time expressed in seconds from the Posix epoch.
#    changeover - Julian Day on which the Gregorian calendar was adopted
#             in the target locale.
#
# Results:
#    Returns the given date with "iso8601Year" set to the
#    base year and "iso8601Week" to the week number.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AssignBaseWeek {date baseTime timeZone changeover} {

    variable TZData

    # Find the Julian Day Number corresponding to the base time

    set date2 [GetDateFields $baseTime $TZData($timeZone) $changeover]

    # Calculate the ISO8601 date and transfer the year

    dict set date era CE
    dict set date iso8601Year [dict get $date2 iso8601Year]
    dict set date iso8601Week [dict get $date2 iso8601Week]
    return $date
}

#----------------------------------------------------------------------
#
# AssignBaseJulianDay --
#
#    Determines the base day for a time-of-day conversion.
#
# Parameters:
#    date - Dictionary that is to get the base day
#    baseTime - Base time expressed in seconds from the Posix epoch
#    changeover - Julian day on which the Gregorian calendar was
#             adpoted in the target locale.
#
# Results:
#    Returns the given dictionary augmented with a 'julianDay' field
#    that contains the base day.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AssignBaseJulianDay { date baseTime timeZone changeover } {

    variable TZData

    # Find the Julian Day Number corresponding to the base time

    set date2 [GetDateFields $baseTime $TZData($timeZone) $changeover]
    dict set date julianDay [dict get $date2 julianDay]

    return $date
}

#----------------------------------------------------------------------
#
# InterpretHMSP --
#
#    Interprets a time in the form "hh:mm:ss am".
#
# Parameters:
#    date -- Dictionary containing "hourAMPM", "minute", "second"
#            and "amPmIndicator" fields.
#
# Results:
#    Returns the number of seconds from local midnight.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

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 {}]]

}

#----------------------------------------------------------------------
#
# InterpretHMS --
#
#    Interprets a 24-hour time "hh:mm:ss"
#
# Parameters:
#    date -- Dictionary containing the "hour", "minute" and "second"
#            fields.
#
# Results:
#    Returns the given dictionary augmented with a "secondOfDay"
#    field containing the number of seconds from local midnight.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::InterpretHMS { date } {

    return [expr { ( [dict get $date hour] * 60
             + [dict get $date minute] ) * 60
           + [dict get $date second] }]

}

#----------------------------------------------------------------------
#
# GetSystemTimeZone --
#
#    Determines the system time zone, which is the default for the
#    'clock' command if no other zone is supplied.
#
# Parameters:
#    None.
#
# Results:
#    Returns the system time zone.
#
# Side effects:
#    Stores the sustem time zone in the 'CachedSystemTimeZone'
#    variable, since determining it may be an expensive process.
#
#----------------------------------------------------------------------

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
    } elseif { [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
    }

}

#----------------------------------------------------------------------
#
# ConvertLegacyTimeZone --
#
#    Given an alphanumeric time zone identifier and the system
#    time zone, convert the alphanumeric identifier to an
#    unambiguous time zone.
#
# Parameters:
#    tzname - Name of the time zone to convert
#
# Results:
#    Returns a time zone name corresponding to tzname, but
#    in an unambiguous form, generally +hhmm.
#
# This procedure is implemented primarily to allow the parsing of
# RFC822 date/time strings.  Processing a time zone name on input
# is not recommended practice, because there is considerable room
# for ambiguity; for instance, is BST Brazilian Standard Time, or
# British Summer Time?
#
#----------------------------------------------------------------------

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"
    } else {
    return [dict get $LegacyTimeZone $tzname]
    }

}

#----------------------------------------------------------------------
#
# SetupTimeZone --
#
#    Given the name or specification of a time zone, sets up
#    its in-memory data.
#
# Parameters:
#    tzname - Name of a time zone
#
# Results:
#    Unless the time zone is ':localtime', sets the TZData array
#    to contain the lookup table for local<->UTC conversion.
#    Returns an error if the time zone cannot be parsed.
#
#----------------------------------------------------------------------

proc ::tcl::clock::SetupTimeZone { timezone } {

    variable TZData

    if {! [info exists TZData($timezone)] } {
    variable MINWIDE
    if { $timezone eq {:localtime} } {

        # Nothing to do, we'll convert using the localtime function

    } elseif { [regexp {^([-+])(\d\d)(?::?(\d\d)(?::?(\d\d))?)?} $timezone \
            -> s hh mm ss] } {

        # Make a fixed offset

        ::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 {:} } {
        
        # Convert using a time zone file

        if { 
        [catch {
            LoadTimeZoneFile [string range $timezone 1 end]
        }]
        && [catch {
            LoadZoneinfoFile [string range $timezone 1 end]
        }]
        } {
        return -code error \
            -errorcode [list CLOCK badTimeZone $timezone] \
            "time zone \"$timezone\" not found"
        }
        
    } elseif { ![catch {ParsePosixTimeZone $timezone} tzfields] } {
        
        # This looks like a POSIX time zone - try to process it

        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 {

        # We couldn't parse this as a POSIX time zone.  Try
        # again with a time zone file - this time without a colon

        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
}

#----------------------------------------------------------------------
#
# GuessWindowsTimeZone --
#
#    Determines the system time zone on windows.
#
# Parameters:
#    None.
#
# Results:
#    Returns a time zone specifier that corresponds to the system
#    time zone information found in the Registry.
#
# Bugs:
#    Fixed dates for DST change are unimplemented at present, because
#    no time zone information supplied with Windows actually uses
#    them!
#
# On a Windows system where neither $env(TCL_TZ) nor $env(TZ) is 
# specified, GuessWindowsTimeZone looks in the Registry for the
# system time zone information.  It then attempts to find an entry
# in WinZoneInfo for a time zone that uses the same rules.  If
# it finds one, it returns it; otherwise, it constructs a Posix-style
# time zone string and returns that.
#
#----------------------------------------------------------------------

proc ::tcl::clock::GuessWindowsTimeZone {} {

    variable WinZoneInfo
    variable NoRegistry
    variable TimeZoneBad

    if { [info exists NoRegistry] } {
    return :localtime
    }

    # Dredge time zone information out of the registry

    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
    }
    }] } {

    # Missing values in the Registry - bail out

    return :localtime
    }

    # Make up a Posix time zone specifier if we can't find one.
    # Check here that the tzdata file exists, in case we're running
    # in an environment (e.g. starpack) where tzdata is incomplete.
    # (Bug 1237907)

    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 {
        # I have not been able to find any locale on which
        # Windows converts time zone on a fixed day of the year,
        # hence don't know how to interpret the fields.
        # If someone can inform me, I'd be glad to code it up.
        # For right now, we bail out in such a case.
        return :localtime
        }
        append tzname / [::format %02d $dstHour] \
        : [::format %02d $dstMinute] \
        : [::format %02d $dstSecond]
        if { $stdYear == 0 } {
        append tzname ,M $stdMonth . $stdDayOfMonth . $stdDayOfWeek
        } else {
        # I have not been able to find any locale on which
        # Windows converts time zone on a fixed day of the year,
        # hence don't know how to interpret the fields.
        # If someone can inform me, I'd be glad to code it up.
        # For right now, we bail out in such a case.
        return :localtime
        }
        append tzname / [::format %02d $stdHour] \
        : [::format %02d $stdMinute] \
        : [::format %02d $stdSecond]
    }
    dict set WinZoneInfo $data $tzname
    } 

    return [dict get $WinZoneInfo $data]

}

#----------------------------------------------------------------------
#
# LoadTimeZoneFile --
#
#    Load the data file that specifies the conversion between a
#    given time zone and Greenwich.
#
# Parameters:
#    fileName -- Name of the file to load
#
# Results:
#    None.
#
# Side effects:
#    TZData(:fileName) contains the time zone data
#
#----------------------------------------------------------------------

proc ::tcl::clock::LoadTimeZoneFile { fileName } {
    variable DataDir
    variable TZData

    if { [info exists TZData($fileName)] } {
    return
    }

    # Since an unsafe interp uses the [clock] command in the master,
    # this code is security sensitive.  Make sure that the path name
    # cannot escape the given directory.

    if { ![regexp {^[[.-.][:alpha:]_]+(?:/[[.-.][:alpha:]_]+)*$} $fileName] } {
    return -code error \
        -errorcode [list CLOCK badTimeZone $:fileName] \
        "time zone \":$fileName\" not valid"
    }
    if { [catch {
    source -encoding utf-8 [file join $DataDir $fileName]
    }] } {
    return -code error \
        -errorcode [list CLOCK badTimeZone :$fileName] \
        "time zone \":$fileName\" not found"
    }
    return
}

#----------------------------------------------------------------------
#
# LoadZoneinfoFile --
#
#    Loads a binary time zone information file in Olson format.
#
# Parameters:
#    fileName - Relative path name of the file to load.
#
# Results:
#    Returns an empty result normally; returns an error if no
#    Olson file was found or the file was malformed in some way.
#
# Side effects:
#    TZData(:fileName) contains the time zone data
#
#----------------------------------------------------------------------

proc ::tcl::clock::LoadZoneinfoFile { fileName } {

    variable ZoneinfoPaths

    # Since an unsafe interp uses the [clock] command in the master,
    # this code is security sensitive.  Make sure that the path name
    # cannot escape the given directory.

    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
}

#----------------------------------------------------------------------
#
# ReadZoneinfoFile --
#
#    Loads a binary time zone information file in Olson format.
#
# Parameters:
#    fileName - Name of the time zone (relative path name of the
#           file).
#    fname - Absolute path name of the file.
#
# Results:
#    Returns an empty result normally; returns an error if no
#    Olson file was found or the file was malformed in some way.
#
# Side effects:
#    TZData(:fileName) contains the time zone data
#
#----------------------------------------------------------------------


proc ::tcl::clock::ReadZoneinfoFile {fileName fname} {
    variable MINWIDE
    variable TZData
    if { ![info exists fname] } {
    return -code error "$fileName not found"
    }

    if { [file size $fname] > 262144 } {
    return -code error "$fileName too big"
    }

    # Suck in all the data from the file

    set f [open $fname r]
    fconfigure $f -translation binary
    set d [read $f]
    close $f

    # The file begins with a magic number, sixteen reserved bytes,
    # and then six 4-byte integers giving counts of fileds in the file.

    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"
    }
    # Accept only Posix-style zoneinfo.  Sorry, 'leaps' bigots.
    if { $nLeap != 0 } {
    return -code error "$fileName contains leap seconds"
    }

    # In a version 2 file, we use the second part of the file, which
    # contains 64-bit transition times.

    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
    }

    # Next come ${nTime} transition times, followed by ${nTime} time type
    # codes.  The type codes are unsigned 1-byte quantities.  We insert an
    # arbitrary start time in front of the transitions.

    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]

    # Next come ${nType} time type descriptions, each of which has an
    # offset (seconds east of GMT), a DST indicator, and an index into
    # the abbreviation text.

    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
    }

    # Next come $nChar characters of time zone name abbreviations,
    # which are null-terminated.
    # We build them up into a dictionary indexed by character index,
    # because that's what's in the indices above.

    binary scan $d @${seek}a${nChar} abbrs
    incr seek ${nChar}
    set abbrList [split $abbrs \0]
    set i 0
    set abbrevs {}
    foreach a $abbrList {
    dict set abbrevs $i $a
    incr i [expr { [string length $a] + 1 }]
    }

    # Package up a list of tuples, each of which contains transition time,
    # seconds east of Greenwich, DST flag and time zone abbreviation.

    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]
    }

    # In a version 2 file, there is also a POSIX-style time zone description
    # at the very end of the file.  To get to it, skip over
    # nLeap leap second values (8 bytes each),
    # nIsStd standard/DST indicators and nIsGMT UTC/local indicators.

    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
}

#----------------------------------------------------------------------
#
# ParsePosixTimeZone --
#
#    Parses the TZ environment variable in Posix form
#
# Parameters:
#    tz    Time zone specifier to be interpreted
#
# Results:
#    Returns a dictionary whose values contain the various pieces of
#    the time zone specification.
#
# Side effects:
#    None.
#
# Errors:
#    Throws an error if the syntax of the time zone is incorrect.
#
# The following keys are present in the dictionary:
#    stdName - Name of the time zone when Daylight Saving Time
#          is not in effect.
#    stdSignum - Sign (+, -, or empty) of the offset from Greenwich 
#            to the given (non-DST) time zone.  + and the empty
#            string denote zones west of Greenwich, - denotes east
#            of Greenwich; this is contrary to the ISO convention
#            but follows Posix.
#    stdHours - Hours part of the offset from Greenwich to the given
#           (non-DST) time zone.
#    stdMinutes - Minutes part of the offset from Greenwich to the
#             given (non-DST) time zone. Empty denotes zero.
#    stdSeconds - Seconds part of the offset from Greenwich to the
#             given (non-DST) time zone. Empty denotes zero.
#    dstName - Name of the time zone when DST is in effect, or the
#          empty string if the time zone does not observe Daylight
#          Saving Time.
#    dstSignum, dstHours, dstMinutes, dstSeconds -
#        Fields corresponding to stdSignum, stdHours, stdMinutes,
#        stdSeconds for the Daylight Saving Time version of the
#        time zone.  If dstHours is empty, it is presumed to be 1.
#    startDayOfYear - The ordinal number of the day of the year on which
#             Daylight Saving Time begins.  If this field is
#             empty, then DST begins on a given month-week-day,
#             as below.
#    startJ - The letter J, or an empty string.  If a J is present in
#         this field, then startDayOfYear does not count February 29
#         even in leap years.
#    startMonth - The number of the month in which Daylight Saving Time
#             begins, supplied if startDayOfYear is empty.  If both
#             startDayOfYear and startMonth are empty, then US rules
#             are presumed.
#    startWeekOfMonth - The number of the week in the month in which
#               Daylight Saving Time begins, in the range 1-5.
#               5 denotes the last week of the month even in a
#               4-week month.
#    startDayOfWeek - The number of the day of the week (Sunday=0,
#             Saturday=6) on which Daylight Saving Time begins.
#    startHours - The hours part of the time of day at which Daylight
#             Saving Time begins. An empty string is presumed to be 2.
#    startMinutes - The minutes part of the time of day at which DST begins.
#               An empty string is presumed zero.
#    startSeconds - The seconds part of the time of day at which DST begins.
#               An empty string is presumed zero.
#    endDayOfYear, endJ, endMonth, endWeekOfMonth, endDayOfWeek,
#    endHours, endMinutes, endSeconds -
#        Specify the end of DST in the same way that the start* fields
#        specify the beginning of DST.
#        
# This procedure serves only to break the time specifier into fields.
# No attempt is made to canonicalize the fields or supply default values.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ParsePosixTimeZone { tz } {

    if {[regexp -expanded -nocase -- {
    ^
    # 1 - Standard time zone name
    ([[:alpha:]]+ | <[-+[:alnum:]]+>)
    # 2 - Standard time zone offset, signum
    ([-+]?)
    # 3 - Standard time zone offset, hours
    ([[:digit:]]{1,2})
    (?:
        # 4 - Standard time zone offset, minutes
        : ([[:digit:]]{1,2}) 
        (?: 
            # 5 - Standard time zone offset, seconds
        : ([[:digit:]]{1,2} )
        )?
    )?
    (?:
        # 6 - DST time zone name
        ([[:alpha:]]+ | <[-+[:alnum:]]+>)
        (?:
            (?:
            # 7 - DST time zone offset, signum
            ([-+]?)
            # 8 - DST time zone offset, hours
            ([[:digit:]]{1,2})
            (?:
            # 9 - DST time zone offset, minutes
            : ([[:digit:]]{1,2}) 
            (?: 
                    # 10 - DST time zone offset, seconds
                : ([[:digit:]]{1,2})
            )?
            )?
        )?
            (?:
            ,
            (?:
            # 11 - Optional J in n and Jn form 12 - Day of year
                ( J ? )    ( [[:digit:]]+ )
                        | M
            # 13 - Month number 14 - Week of month 15 - Day of week
            ( [[:digit:]] + ) 
            [.] ( [[:digit:]] + ) 
            [.] ( [[:digit:]] + )
            )
            (?:
            # 16 - Start time of DST - hours
            / ( [[:digit:]]{1,2} )
                (?:
                # 17 - Start time of DST - minutes
                : ( [[:digit:]]{1,2} )
                (?:
                # 18 - Start time of DST - seconds
                : ( [[:digit:]]{1,2} )
                )?
            )?
            )?
            ,
            (?:
            # 19 - Optional J in n and Jn form 20 - Day of year
                ( J ? )    ( [[:digit:]]+ )
                        | M
            # 21 - Month number 22 - Week of month 23 - Day of week
            ( [[:digit:]] + ) 
            [.] ( [[:digit:]] + ) 
            [.] ( [[:digit:]] + )
            )
            (?:
            # 24 - End time of DST - hours
            / ( [[:digit:]]{1,2} )
                (?:
                # 25 - End time of DST - minutes
                : ( [[:digit:]]{1,2} )
                (?:
                # 26 - End time of DST - seconds
                : ( [[: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)] } {

    # it's a good timezone

    return [array get x]

    } else {

    return -code error\
        -errorcode [list CLOCK badTimeZone $tz] \
        "unable to parse time zone specification \"$tz\""

    }

}

#----------------------------------------------------------------------
#
# ProcessPosixTimeZone --
#
#    Handle a Posix time zone after it's been broken out into
#    fields.
#
# Parameters:
#    z - Dictionary returned from 'ParsePosixTimeZone'
#
# Results:
#    Returns time zone information for the 'TZData' array.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ProcessPosixTimeZone { z } {

    variable MINWIDE
    variable TZData

    # Determine the standard time zone name and seconds east of Greenwich

    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]]

    # If there's no daylight zone, we're done

    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]
    }

    # Determine the daylight name

    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 }]
    }

    # Fill in defaults for European or US DST rules
    # US start time is the second Sunday in March
    # EU start time is the last Sunday in March
    # US end time is the first Sunday in November.
    # EU end time is the last Sunday in October

    if { [dict get $z startDayOfYear] eq {} 
     && [dict get $z startMonth] eq {} } {
    if {($stdSignum * $stdHours>=0) && ($stdSignum * $stdHours<=12)} {
        # EU
        dict set z startWeekOfMonth 5
        if {$stdHours>2} {
        dict set z startHours 2
        } else {
        dict set z startHours [expr {$stdHours+1}]
        }
    } else {
        # US
        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 {} } {
    if {($stdSignum * $stdHours>=0) && ($stdSignum * $stdHours<=12)} {
        # EU
        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 {
        # US
        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
    }

    # Put DST in effect in all years from 1916 to 2099.

    for { set y 1916 } { $y < 2099 } { 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
    
}    

#----------------------------------------------------------------------
#
# DeterminePosixDSTTime --
#
#    Determines the time that Daylight Saving Time starts or ends
#    from a Posix time zone specification.
#
# Parameters:
#    z - Time zone data returned from ParsePosixTimeZone.
#        Missing fields are expected to be filled in with
#        default values.
#    bound - The word 'start' or 'end'
#    y - The year for which the transition time is to be determined.
#
# Results:
#    Returns the transition time as a count of seconds from
#    the epoch.  The time is relative to the wall clock, not UTC.
#
#----------------------------------------------------------------------

proc ::tcl::clock::DeterminePosixDSTTime { z bound y } {

    variable FEB_28

    # Determine the start or end day of DST

    set date [dict create era CE year $y]
    set doy [dict get $z ${bound}DayOfYear]
    if { $doy ne {} } {

    # Time was specified as a day of the year

    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 {

    # Time was specified as a day of the week within a month

    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 }]

}

#----------------------------------------------------------------------
#
# GetLocaleEra --
#
#    Given local time expressed in seconds from the Posix epoch,
#    determine localized era and year within the era.
#
# Parameters:
#    date - Dictionary that must contain the keys, 'localSeconds',
#           whose value is expressed as the appropriate local time;
#           and 'year', whose value is the Gregorian year.
#    etable - Value of the LOCALE_ERAS key in the message catalogue
#             for the target locale.
#
# Results:
#    Returns the dictionary, augmented with the keys, 'localeEra'
#    and 'localeYear'.
#
#----------------------------------------------------------------------

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

}

#----------------------------------------------------------------------
#
# GetJulianDayFromEraYearDay --
#
#    Given a year, month and day on the Gregorian calendar, determines
#    the Julian Day Number beginning at noon on that date.
#
# Parameters:
#    date -- A dictionary in which the 'era', 'year', and
#        'dayOfYear' slots are populated. The calendar in use
#        is determined by the date itself relative to:
#       changeover -- Julian day on which the Gregorian calendar was
#        adopted in the current locale.
#
# Results:
#    Returns the given dictionary augmented with a 'julianDay' key
#    whose value is the desired Julian Day Number, and a 'gregorian'
#    key that specifies whether the calendar is Gregorian (1) or
#    Julian (0).
#
# Side effects:
#    None.
#
# Bugs:
#    This code needs to be moved to the C layer.
#
#----------------------------------------------------------------------

proc ::tcl::clock::GetJulianDayFromEraYearDay {date changeover} {

    # Get absolute year number from the civil year

    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 }]

    # Try the Gregorian calendar first.

    dict set date gregorian 1
    set jd [expr { 1721425
           + [dict get $date dayOfYear]
           + ( 365 * $ym1 )
           + ( $ym1 / 4 )
           - ( $ym1 / 100 )
           + ( $ym1 / 400 ) }]
    
    # If the date is before the Gregorian change, use the Julian calendar.

    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
}

#----------------------------------------------------------------------
#
# GetJulianDayFromEraYearMonthWeekDay --
#
#    Determines the Julian Day number corresponding to the nth
#    given day-of-the-week in a given month.
#
# Parameters:
#    date - Dictionary containing the keys, 'era', 'year', 'month'
#           'weekOfMonth', 'dayOfWeek', and 'dayOfWeekInMonth'.
#    changeover - Julian Day of adoption of the Gregorian calendar
#
# Results:
#    Returns the given dictionary, augmented with a 'julianDay' key.
#
# Side effects:
#    None.
#
# Bugs:
#    This code needs to be moved to the C layer.
#
#----------------------------------------------------------------------

proc ::tcl::clock::GetJulianDayFromEraYearMonthWeekDay {date changeover} {

    # Come up with a reference day; either the zeroeth day of the
    # given month (dayOfWeekInMonth >= 0) or the seventh day of the
    # following month (dayOfWeekInMonth < 0)

    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

}

#----------------------------------------------------------------------
#
# IsGregorianLeapYear --
#
#    Determines whether a given date represents a leap year in the
#    Gregorian calendar.
#
# Parameters:
#    date -- The date to test.  The fields, 'era', 'year' and 'gregorian'
#            must be set.
#
# Results:
#    Returns 1 if the year is a leap year, 0 otherwise.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

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
    }

}

#----------------------------------------------------------------------
#
# WeekdayOnOrBefore --
#
#    Determine the nearest day of week (given by the 'weekday'
#    parameter, Sunday==0) on or before a given Julian Day.
#
# Parameters:
#    weekday -- Day of the week
#    j -- Julian Day number
#
# Results:
#    Returns the Julian Day Number of the desired date.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::WeekdayOnOrBefore { weekday j } {

    set k [expr { ( $weekday + 6 )  % 7 }]
    return [expr { $j - ( $j - $k ) % 7 }]

}

#----------------------------------------------------------------------
#
# BSearch --
#
#    Service procedure that does binary search in several places
#    inside the 'clock' command.
#
# Parameters:
#    list - List of lists, sorted in ascending order by the
#           first elements
#    key - Value to search for
#
# Results:
#    Returns the index of the greatest element in $list that is less
#    than or equal to $key.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

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 } {

    # At this point, we know that
    #   $k >= [lindex $list $l 0]
    #   Either $u == [llength $list] or else $k < [lindex $list $u+1 0]
    # We find the midpoint of the interval {l,u} rounded UP, compare
    # against it, and set l or u to maintain the invariant.  Note
    # that the interval shrinks at each step, guaranteeing convergence.

    set m [expr { ( $l + $u + 1 ) / 2 }]
    if { $key >= [lindex $list $m 0] } {
        set l $m
    } else {
        set u [expr { $m - 1 }]
    }
    }

    return $l
}

#----------------------------------------------------------------------
#
# clock add --
#
#    Adds an offset to a given time.
#
# Syntax:
#    clock add clockval ?count unit?... ?-option value?
#
# Parameters:
#    clockval -- Starting time value
#    count -- Amount of a unit of time to add
#    unit -- Unit of time to add, must be one of:
#            years year months month weeks week
#            days day hours hour minutes minute
#            seconds second
#
# Options:
#    -gmt BOOLEAN
#        (Deprecated) Flag synonymous with '-timezone :GMT'
#    -timezone ZONE
#        Name of the time zone in which calculations are to be done.
#    -locale NAME
#        Name of the locale in which calculations are to be done.
#        Used to determine the Gregorian change date.
#
# Results:
#    Returns the given time adjusted by the given offset(s) in
#    order.
#
# Notes:
#    It is possible that adding a number of months or years will adjust
#    the day of the month as well.  For instance, the time at
#    one month after 31 January is either 28 or 29 February, because
#    February has fewer than 31 days.
#
#----------------------------------------------------------------------

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 {
            return -code error \
            -errorcode [list CLOCK badSwitch $a] \
            "bad switch \"$a\",\
                         must be -gmt, -locale or -timezone"
        }
        }
    }
    }

    # Check options for validity

    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 $gmt] } {
    return -code error \
        "expected boolean value but got \"$gmt\""
    } else {
    if { $gmt } {
        set timezone :GMT
    }
    }

    EnterLocale $locale oldLocale
    
    set changeover [mc GREGORIAN_CHANGE_DATE]

    if {[catch {SetupTimeZone $timezone} retval opts]} {
    dict unset opts -errorinfo
    return -options $opts $retval
    }

    set status [catch {

    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 {
            error "unknown unit \"$unit\", must be \
                        years, months, weeks, days, hours, minutes or seconds" \
              "unknown unit \"$unit\", must be \
                        years, months, weeks, days, hours, minutes or seconds" \
            [list CLOCK badUnit $unit]
        }
        }
    }
    } result opts]

    # Restore the locale

    if { [info exists oldLocale] } {
    mclocale $oldLocale
    }

    if { $status == 1 } {
    if { [lindex [dict get $opts -errorcode] 0] eq {CLOCK} } {
        dict unset opts -errorinfo
    }
    return -options $opts $result
    } else {
    return $clockval
    }

}

#----------------------------------------------------------------------
#
# AddMonths --
#
#    Add a given number of months to a given clock value in a given
#    time zone.
#
# Parameters:
#    months - Number of months to add (may be negative)
#    clockval - Seconds since the epoch before the operation
#    timezone - Time zone in which the operation is to be performed
#
# Results:
#    Returns the new clock value as a number of seconds since
#    the epoch.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AddMonths { months clockval timezone changeover } {

    variable DaysInRomanMonthInCommonYear
    variable DaysInRomanMonthInLeapYear
    variable TZData

    # Convert the time to year, month, day, and fraction of day.

    set date [GetDateFields $clockval $TZData($timezone) $changeover]
    dict set date secondOfDay [expr { [dict get $date localSeconds]
                      % 86400 }]
    dict set date tzName $timezone

    # Add the requisite number of months

    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 the date doesn't exist in the current month, repair it

    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
    }

    # Reconvert to a number of seconds

    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]

}

#----------------------------------------------------------------------
#
# AddDays --
#
#    Add a given number of days to a given clock value in a given
#    time zone.
#
# Parameters:
#    days - Number of days to add (may be negative)
#    clockval - Seconds since the epoch before the operation
#    timezone - Time zone in which the operation is to be performed
#    changeover - Julian Day on which the Gregorian calendar was adopted
#             in the target locale.
#
# Results:
#    Returns the new clock value as a number of seconds since
#    the epoch.
#
# Side effects:
#    None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AddDays { days clockval timezone changeover } {

    variable TZData

    # Convert the time to Julian Day

    set date [GetDateFields $clockval $TZData($timezone) $changeover]
    dict set date secondOfDay [expr { [dict get $date localSeconds]
                      % 86400 }]
    dict set date tzName $timezone

    # Add the requisite number of days

    dict incr date julianDay $days

    # Reconvert to a number of seconds

    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]

}

#----------------------------------------------------------------------
#
# mc --
#
#    Wrapper around ::msgcat::mc that caches the result according
#    to the locale.
#
# Parameters:
#    Accepts the name of the message to retrieve.
#
# Results:
#    Returns the message text.
#
# Side effects:
#    Caches the message text.
#
# Notes:
#    Only the single-argument version of [mc] is supported.
#
#----------------------------------------------------------------------

proc ::tcl::clock::mc { name } {
    variable McLoaded
    set Locale [mclocale]
    if { [dict exists $McLoaded $Locale $name] } {
    return [dict get $McLoaded $Locale $name]
    } else {
    set val [::msgcat::mc $name]
    dict set McLoaded $Locale $name $val
    return $val
    }
}

#----------------------------------------------------------------------
#
# ClearCaches --
#
#    Clears all caches to reclaim the memory used in [clock]
#
# Parameters:
#    None.
#
# Results:
#    None.
#
# Side effects:
#    Caches are cleared.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ClearCaches {} {

    variable FormatProc
    variable LocaleNumeralCache
    variable McLoaded
    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 {}
    set McLoaded {}
    catch {unset CachedSystemTimeZone}
    set TimeZoneBad {}
    InitTZData

}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.0 [PHP 7 Update] [25.02.2019] maintained by KaizenLouie | C99Shell Github | Generation time: 0.0317 ]--