Diff
Not logged in

Differences From Artifact [26de7b7733]:

To Artifact [6f5cd94904]:


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#----------------------------------------------------------------------
#
# Copyright (c) 2004 by Kevin B. Kenny.  All rights reserved.
# 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.20 2005/11/04 20:13:30 kennykb Exp $
#
#----------------------------------------------------------------------

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








|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#----------------------------------------------------------------------
#
# Copyright (c) 2004 by Kevin B. Kenny.  All rights reserved.
# 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.21 2005/11/29 22:50:58 kennykb Exp $
#
#----------------------------------------------------------------------

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

119
120
121
122
123
124
125

126
127
128
129
130
131
132
	    {-9223372036854775808 0 0 GMT}
	}
	set TZData(:GMT) $TZData(:Etc/GMT)
	set TZData(:Etc/UTC) {
	    {-9223372036854775808 0 0 UTC}
	}
	set TZData(:UTC) $TZData(:Etc/UTC)

    }
    InitTZData

    # Define the message catalog for the root locale.

    ::msgcat::mcmset {} {
	AM {am}







>







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
	    {-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}
636
637
638
639
640
641
642


643
644
645
646
647
648
649
# 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 } {



    set format {}

    # Check the count of args

    if { [llength $args] < 1 || [llength $args] % 2 != 1 } {
	return -code error \
	    -errorcode [list CLOCK wrongNumArgs] \







>
>







637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# 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 TZData

    set format {}

    # Check the count of args

    if { [llength $args] < 1 || [llength $args] % 2 != 1 } {
	return -code error \
	    -errorcode [list CLOCK wrongNumArgs] \
715
716
717
718
719
720
721

722
723


724

725
726
727
728
729
730


731
732
733
734
735
736
737

	# Map away the locale-dependent composite format groups

	set format [LocalizeFormat $locale $format]

	# Convert the given time to local time.
	

	set date [dict create seconds $clockval]
	set date [ConvertUTCToLocal $date[set date {}] $timezone]


	

	# Extract the fields of the date.
	
	set date [GetJulianDay $date[set date {}]]
	set date [GetGregorianEraYearDay $date[set date {}]]
	set date [GetMonthDay $date[set date {}]]
	set date [GetYearWeekDay $date[set date {}]]


	
	# Format the result
	
	set state {}
	set retval {}
	foreach char [split $format {}] {
	    switch -exact -- $state {







>
|
|
>
>
|
>

|
|
<
<
<
>
>







718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734



735
736
737
738
739
740
741
742
743

	# Map away the locale-dependent composite format groups

	set format [LocalizeFormat $locale $format]

	# Convert the given time to local time.
	
	# 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 the fields of the date.

	set date [GetDateFields $clockval \



		      $TZData($timezone) \
		      [mc GREGORIAN_CHANGE_DATE]]
	
	# Format the result
	
	set state {}
	set retval {}
	foreach char [split $format {}] {
	    switch -exact -- $state {
1228
1229
1230
1231
1232
1233
1234









1235
1236
1237
1238
1239
1240
1241
1242
1243
1244

1245
1246
1247
1248
1249
1250
1251
# Results:
#	Returns the date and time extracted from the string in seconds
#	from the epoch
#
#----------------------------------------------------------------------

proc ::tcl::clock::FreeScan { string base timezone locale } {










    # Extract year, month and day from the base time for the
    # parser to use as defaults

    set date [GetMonthDay \
		  [GetGregorianEraYearDay \
		       [GetJulianDay \
			    [ConvertUTCToLocal \
				 [dict create seconds $base] \
				 $timezone]]]]

    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.








>
>
>
>
>
>
>
>
>




|
<
<
<
|
|
>







1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254



1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
# 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) \
		  2299161]
    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.

1290
1291
1292
1293
1294
1295
1296

1297
1298
1299
1300
1301
1302
1303
    # indicator ( 1 == yes, 0 == no, -1 == unknown ). We make it into
    # a time zone indicator of +-hhmm.
    
    if { [llength $parseZone] > 0 } {
	foreach { minEast dstFlag } $parseZone break
	set timezone [FormatNumericTimeZone \
			  [expr { 60 * $minEast + 3600 * $dstFlag }]]

    }
    dict set date tzName $timezone

    # Assemble date, time, zone into seconds-from-epoch

    set date [GetJulianDayFromEraYearMonthDay $date[set date {}]]
    if { $parseTime ne {} } {







>







1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
    # indicator ( 1 == yes, 0 == no, -1 == unknown ). We make it into
    # a time zone indicator of +-hhmm.
    
    if { [llength $parseZone] > 0 } {
	foreach { minEast dstFlag } $parseZone break
	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 {}]]
    if { $parseTime ne {} } {
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355

1356
1357
1358
1359
1360
1361
1362
    }

    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 {}]]
    set seconds [dict get $date seconds]

    # Do relative times

    if { [llength $parseRel] > 0 } {
	foreach { relMonth relDay relSecond } $parseRel break
	set seconds [add $seconds \
			 $relMonth months $relDay days $relSecond seconds \
			 -timezone $timezone -locale $locale]
    }	

    # Do relative weekday
    
    if { [llength $parseWeekday] > 0 } {

	foreach {dayOrdinal dayOfWeek} $parseWeekday break
	set date2 [GetJulianDay \
		       [ConvertUTCToLocal \
			    [dict create seconds $seconds] \
			    $timezone]]
	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 {}]]

	set seconds [dict get $date2 seconds]

    }

    # Do relative month

    if { [llength $parseOrdinalMonth] > 0 } {







|
















|
<
<
<
















|
>







1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349



1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
    }

    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) 2299161]
    set seconds [dict get $date seconds]

    # Do relative times

    if { [llength $parseRel] > 0 } {
	foreach { relMonth relDay relSecond } $parseRel break
	set seconds [add $seconds \
			 $relMonth months $relDay days $relSecond seconds \
			 -timezone $timezone -locale $locale]
    }	

    # Do relative weekday
    
    if { [llength $parseWeekday] > 0 } {

	foreach {dayOrdinal dayOfWeek} $parseWeekday break
	set date2 [GetDateFields $seconds $TZData($timezone) 2299161]



	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) \
		       2299161]
	set seconds [dict get $date2 seconds]

    }

    # Do relative month

    if { [llength $parseOrdinalMonth] > 0 } {
1840
1841
1842
1843
1844
1845
1846

1847
1848
1849
1850
1851
1852
1853
    # Clean up any unfinished format groups

    append re $state \\s*\$

    # Build the procedure

    set procBody {}

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







>







1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
    # 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] \
1880
1881
1882
1883
1884
1885
1886

1887





1888


1889
1890
1891
1892
1893
1894
1895
			+ ( 86400 * wide([dict get $date julianDay]) )
			+ [dict get $date secondOfDay] }]
	}
    }

    if { ![dict exists $fieldSet seconds] 
	 && ![dict exists $fieldSet starDate] } {

	append procBody {





	    set date [::tcl::clock::ConvertLocalToUTC $date[set date {}]]


	}
    }

    # Return result

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








>
|
>
>
>
>
>
|
>
>







1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
			+ ( 86400 * wide([dict get $date julianDay]) )
			+ [dict get $date secondOfDay] }]
	}
    }

    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
	    set date [::tcl::clock::ConvertLocalToUTC $date[set date {}] \
			  $TZData($timeZone) \
			  [mc GREGORIAN_CHANGE_DATE]]
	}
    }

    # Return result

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

2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
    if { $z != 0 } {
	append retval [::format %02d $z]
    }
    return $retval

}


#----------------------------------------------------------------------
#
# FormatStarDate --
#
#	Formats a date as a StarDate.
#
# Parameters:







<







2490
2491
2492
2493
2494
2495
2496

2497
2498
2499
2500
2501
2502
2503
    if { $z != 0 } {
	append retval [::format %02d $z]
    }
    return $retval

}


#----------------------------------------------------------------------
#
# FormatStarDate --
#
#	Formats a date as a StarDate.
#
# Parameters:
2677
2678
2679
2680
2681
2682
2683
2684


2685
2686
2687
2688
2689
2690
2691
2692

2693
2694
2695
2696
2697
2698
2699
#	Returns the dictionary with the current year assigned.
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AssignBaseYear { date baseTime timeZone } {



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

    set date2 [dict create seconds $baseTime]
    set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone]
    set date2 [GetJulianDay $date2[set date2 {}]]
    set date2 [GetGregorianEraYearDay $date2[set date2 {}]]


    # Store the converted year

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

    return $date







|
>
>




<
<
|
<
>







2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710


2711

2712
2713
2714
2715
2716
2717
2718
2719
#	Returns the dictionary with the current year assigned.
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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

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

		   [mc GREGORIAN_CHANGE_DATE]]

    # Store the converted year

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

    return $date
2717
2718
2719
2720
2721
2722
2723


2724
2725
2726
2727
2728
2729

2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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



    # Find the Julian Day Number corresponding to the base time

    set date2 [dict create seconds $baseTime]
    set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone]
    set date2 [GetJulianDay $date2[set date2 {}]]


    # Calculate the ISO8601 date and transfer the year

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

#----------------------------------------------------------------------
#







>
>



<
<
|
>



<







2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748


2749
2750
2751
2752
2753

2754
2755
2756
2757
2758
2759
2760
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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

    variable TZData

    # Find the Julian Day Number corresponding to the base time



    set date2 [GetDateFields $baseTime $TZData($timeZone) \
		   [mc GREGORIAN_CHANGE_DATE]]

    # Calculate the ISO8601 date and transfer the year


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

#----------------------------------------------------------------------
#
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770

2771
2772
2773
2774
2775
2776
2777
#	Returns the dictionary with the base year and month assigned.
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::AssignBaseMonth { date baseTime timeZone } {

    # Find the Julian Day Number corresponding to the base time

    set date2 [dict create seconds $baseTime]
    set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone]
    set date2 [GetJulianDay $date2[set date2 {}]]

    # Find the Gregorian year corresponding to that Julian Day

    set date2 [GetGregorianEraYearDay $date2[set date2 {}]]
    set date2 [GetMonthDay $date2[set date2 {}]]

    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

}








|

<
|
<
<
<

|

<
|
>







2772
2773
2774
2775
2776
2777
2778
2779
2780

2781



2782
2783
2784

2785
2786
2787
2788
2789
2790
2791
2792
2793
#	Returns the dictionary with the base year and month assigned.
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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


    variable TZData




    # Find the year and month corresponding to the base time


    set date2 [GetDateFields $baseTime $TZData($timezone) \
		   [mc GREGORIAN_CHANGE_DATE]]
    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

}

2792
2793
2794
2795
2796
2797
2798


2799
2800
2801
2802
2803
2804

2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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



    # Find the Julian Day Number corresponding to the base time

    set date2 [dict create seconds $baseTime]
    set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone]
    set date2 [GetJulianDay $date2[set date2 {}]]


    # Calculate the ISO8601 date and transfer the year

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

#----------------------------------------------------------------------







>
>



<
<
|
>



<







2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819


2820
2821
2822
2823
2824

2825
2826
2827
2828
2829
2830
2831
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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

    variable TZData

    # Find the Julian Day Number corresponding to the base time



    set date2 [GetDateFields $baseTime $TZData($timeZone) \
		   [mc GREGORIAN_CHANGE_DATE]]

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

#----------------------------------------------------------------------
2828
2829
2830
2831
2832
2833
2834


2835
2836
2837
2838
2839
2840

2841
2842
2843
2844
2845
2846
2847
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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



    # Find the Julian Day Number corresponding to the base time

    set date2 [dict create seconds $baseTime]
    set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone]
    set date2 [GetJulianDay $date2[set date2 {}]]

    dict set date julianDay [dict get $date2 julianDay]

    return $date
}

#----------------------------------------------------------------------
#







>
>



<
<
|
>







2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855


2856
2857
2858
2859
2860
2861
2862
2863
2864
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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

    variable TZData

    # Find the Julian Day Number corresponding to the base time



    set date2 [GetDateFields $baseTime $TZData($timeZone) \
		   [mc GREGORIAN_CHANGE_DATE]]
    dict set date julianDay [dict get $date2 julianDay]

    return $date
}

#----------------------------------------------------------------------
#
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
    if { ![dict exists $LegacyTimeZone $tzname] } {
	return -code error -errorcode [list CLOCK badTZName $tzname] \
	    "time zone \"$tzname\" not found"
    } else {
	return [dict get $LegacyTimeZone $tzname]
    }

}

#----------------------------------------------------------------------
#
# ConvertLocalToUTC --
#
#	Given a time zone and nominal local seconds, compute seconds
#	of UTC time from the Posix epoch.
#
# Parameters:
#	date - Dictionary populated with the 'localSeconds' and
#	       'tzName' fields
#
# Results:
#	Returns the given dictionary augmented with a 'seconds' field.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ConvertLocalToUTC { date } {

    variable TZData

    set timezone [dict get $date tzName]
    if { $timezone eq ":localtime" } {

	# Convert using the mktime function if possible

	if { [catch { 
	    ConvertLocalToUTCViaC [dict get $date localSeconds]
	} result opts] } {
	    dict unset opts -errorinfo
	    return -options $opts $result
	}
	dict set date seconds $result
	return $date

    } else {

	# Get the time zone data

	if { [catch { SetupTimeZone $timezone } retval opts] } {
	    dict unset opts -errorinfo
	    return -options $opts $retval
	}
	
	# Initially assume that local == UTC, and locate the last time
	# conversion prior to that time.  Get the offset from that,
	# and look up again.  If that lookup finds a different offset,
	# continue looking until we find an offset that we found
	# before.  The check for "any offset previously found" rather
	# than "the same offset" avoids an endless loop if we try to
	# convert a non-existent time, for example 2:30am during the
	# US spring DST change.
	
	set localseconds [dict get $date localSeconds]
	set utcseconds(0) $localseconds
	set seconds $localseconds
	while { 1 } {
	    set i [BSearch $TZData($timezone) $seconds]
	    set offset [lindex $TZData($timezone) $i 1]
	    if { [info exists utcseconds($offset)] } {
		dict set date seconds $utcseconds($offset)
		return $date
	    } else {
		set seconds [expr { $localseconds - $offset }]
		set utcseconds($offset) $seconds
	    }
	}
	
	# In the absolute worst case, the loop above can visit each tzdata
	# row only once, so it's guaranteed to terminate.
	
	error "in ConvertLocalToUTC, can't happen"
    }

}

#----------------------------------------------------------------------
#
# ConvertLocalToUTCViaC --
#
#	Given seconds of nominal local time, compute seconds from the
#	Posix epoch.	
#
# Parameters:
#	localSeconds - Seconds of nominal local time
#
# Results:
#	Returns the seconds from the epoch.  May throw an error if
#	the time is to large/small to represent, or if 'mktime' is
#	not present in the C library.
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ConvertLocalToUTCViaC { localSeconds } {

    set date [dict create localSeconds $localSeconds]
    set date [GetJulianDay $date[set date {}]]
    set date [GetGregorianEraYearDay $date[set date {}]]
    set date [GetMonthDay $date[set date {}]]
    set retval \
	[Mktime \
	     [dict get $date year] \
	     [dict get $date month] \
	     [dict get $date dayOfMonth] \
	     [expr { $localSeconds / 3600 % 24 }] \
	     [expr { $localSeconds / 60 % 60 }] \
	     [expr { $localSeconds % 60 }]]
    return $retval
}

#----------------------------------------------------------------------
#
# ConvertUTCToLocal --
#
#	Given the seconds from the Posix epoch, compute seconds of
#	nominal local time.
#
# Parameters:
#	date - Dictionary populated on entry with the 'seconds' field
#
# Results:
#	The given dictionary is returned, augmented with 'localSeconds',
#	'tzOffset', and 'tzName' fields.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ConvertUTCToLocal { date timezone } {

    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
    }

    if { $timezone eq {:localtime} } {

	# Convert using the localtime function
	
	if { [catch {
	    ConvertUTCToLocalViaC $date
	} retval opts] } {
	    dict unset opts -errorinfo
	    return -options $opts $retval
	}
	return $retval
    }

    # Find the most recent transition in the time zone data

    set i [BSearch $TZData($timezone) [dict get $date seconds]]
    set row [lindex $TZData($timezone) $i]
    foreach { junk1 offset junk2 name } $row break

    # Add appropriate offset to convert Greenwich to local, and return
    # the local time

    dict set date localSeconds [expr { [dict get $date seconds] + $offset }]
    dict set date tzOffset $offset
    dict set date tzName $name

    return $date

}

#----------------------------------------------------------------------
#
# ConvertUTCToLocalViaC --
#
#	Convert local time using the C localtime function
#
# Parameters:
#	date - Dictionary populated on entry with the 'seconds'
#	       and 'timeZone' fields.
#
# Results:
#	The given dictionary is returned, augmented with 'localSeconds',
#	'tzOffset', and 'tzName' fields.
#
#----------------------------------------------------------------------

proc ::tcl::clock::ConvertUTCToLocalViaC { date } {

    # Get y-m-d-h-m-s from the C library

    set gmtSeconds [dict get $date seconds]
    set localFields [Localtime $gmtSeconds]
    set date2 [dict create]
    foreach key { 
	year month dayOfMonth hour minute second 
    } value $localFields {
	dict set date2 $key $value
    }
    dict set date2 era CE

    # Convert to Julian Day

    set date2 [GetJulianDayFromEraYearMonthDay $date2[set date2 {}]]

    # Reconvert to seconds from the epoch in local time.

    set localSeconds [expr { ( ( ( wide([dict get $date2 julianDay]) 
				   * 24
				   + wide([dict get $date2 hour]) ) 
				 * 60
				 + wide([dict get $date2 minute]) )
			       * 60
			       + wide([dict get $date2 second]) )
			     - 210866803200 }]
 
    # Determine the name and offset of the timezone

    set diff [expr { $localSeconds - $gmtSeconds }]
    if { $diff <= 0 } {
	set signum -
	set delta [expr { - $diff }]
    } else {
	set signum +
	set delta $diff
    }
    set hh [::format %02d [expr { $delta / 3600 }]]
    set mm [::format %02d [expr { ($delta / 60 )
				  % 60 }]]
    set ss [::format %02d [expr { $delta % 60 }]]

    set zoneName $signum$hh$mm
    if { $ss ne {00} } {
	append zoneName $ss
    }

    # Fix the dictionary

    dict set date localSeconds $localSeconds
    dict set date tzOffset $diff
    dict set date tzName $zoneName
    return $date

}

#----------------------------------------------------------------------
#
# SetupTimeZone --
#
#	Given the name or specification of a time zone, sets up







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







3001
3002
3003
3004
3005
3006
3007



















































































































































































































































3008
3009
3010
3011
3012
3013
3014
    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
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
	dict set date localeEra [lindex $etable $index 1]
	dict set date localeYear [expr { [dict get $date year] 
					 - [lindex $etable $index 2] }]
    }
    return $date

}
#----------------------------------------------------------------------
#
# GetJulianDay --
#
#	Given the seconds from the Posix epoch, derives the Julian
#	day number.
#
# Parameters:
#	date - Dictionary containing the date fields.  On input, 
#	       populated with a 'localSeconds' field that gives the
#	       nominal seconds from the epoch (in the local time zone,
#	       rather than UTC).
#
# Results:
#	Returns the given dictionary, augmented by a 'julianDay'
#	field that gives the Julian Day Number at noon of the current
#	date.
#
#----------------------------------------------------------------------

proc ::tcl::clock::GetJulianDay { date } {

    set secs [dict get $date localSeconds]

    return [dict set date julianDay \
		[expr { ( $secs + 210866803200 )
			/ 86400 }]]

}

#----------------------------------------------------------------------
#
# GetGregorianEraYearDay --
#
#	Given the time from the Posix epoch and the current time zone,
#	develops the era, year, and day of year in the Gregorian calendar.
#
# Parameters:
#	date - Dictionary containing the date fields. On input, populated
#	       with the 'julianDay' key whose value is the Julian Day Number.
#
# Results:
#	Returns the given dictionary with the 'gregorian', 'era', 
#	'year', and 'dayOfYear' populated.
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::GetGregorianEraYearDay { date } {

    set jday [dict get $date julianDay]

    set changeover [mc GREGORIAN_CHANGE_DATE]

    if { $jday >= $changeover } {

	# Gregorian date

	dict set date gregorian 1

	# Calculate number of days since 1 January, 1 CE

	set day [expr { $jday - 1721425 - 1 }]

	# Calculate number of 400 year cycles

	set year 1
	set n [expr { $day / 146097 }]
	incr year [expr { 400 * $n }]
	set day [expr { $day % 146097 }]

	# Calculate number of centuries in the current cycle

	set n [expr { $day / 36524 }]
	set day [expr { $day % 36524 }]
	if { $n > 3 } {
	    set n 3		     ;  # 31 December 2000, for instance
	    incr day 36524	     ;	# is last day of 400 year cycle
        }
	incr year [expr { 100 * $n }]

    } else {

	# Julian date

	dict set date gregorian 0

	# Calculate days since 0 January, 1 CE Julian

	set day [expr { $jday - 1721423 - 1 }]
	set year 1
	
    }

    # Calculate number of 4-year cycles in current century (or in
    # the Common Era, if the calendar is Julian)

    set n [expr { $day / 1461 }]
    set day [expr { $day % 1461 }]
    incr year [expr { 4 * $n }]

    # Calculate number of years in current 4-year cycle

    set n [expr { $day / 365 }]
    set day [expr { $day % 365 }]
    if { $n > 3 } {
	set n 3				;# 31 December in a leap year
	incr day 365
    }
    incr year $n

    # Calculate the era

    if { $year <= 0 } {
	dict set date year [expr { 1 - $year }]
	dict set date era BCE
    } else {
	dict set date year $year
	dict set date era CE
    }

    # Return day of the year

    dict set date dayOfYear [expr { $day + 1 }]

    return $date

}

#----------------------------------------------------------------------
#
# GetMonthDay --
#
#	Given the ordinal number of the day within the year, determines
#	month and day of month in the Gregorian calendar.
#
# Parameters:
#	date - Dictionary containing the date fields. On input, populated
#	       with the 'era', 'gregorian', 'year' and 'dayOfYear' fields.
#
# Results:
#	Returns the given dictionary with the 'month' and 'dayOfMonth' 
#	fields populated.
#
# Side effects:
#	None.
#
#----------------------------------------------------------------------

proc ::tcl::clock::GetMonthDay { date } {

    variable DaysInRomanMonthInCommonYear
    variable DaysInRomanMonthInLeapYear

    set day [dict get $date dayOfYear]
    if { [IsGregorianLeapYear $date] } {
	set hath $DaysInRomanMonthInLeapYear
    } else {
	set hath $DaysInRomanMonthInCommonYear
    }
    set month 1
    foreach n $hath {
	if { $day <= $n } {
	    break
	}
	incr month
	incr day [expr { -$n }]
    }
    dict set date month $month
    dict set date dayOfMonth $day

    return $date

}

#----------------------------------------------------------------------
#
# GetYearWeekDay
#
#	Given a julian day number, fiscal year, fiscal week,
#	and day of week in the ISO8601 calendar.
#
# Parameters:
#	
#	date - Dictionary where the 'julianDay' field is populated.
#	daysInFirstWeek - (Optional) Parameter giving the minimum number
#			  of days in the first week of a year.  Default is 4.
#
# Results:
#	Returns the given dictionary with values filled in for the
#	three given keys.
#
# Side effects:
#	None.
#
# Bugs:
#	Since ISO8601 week numbering is defined only for the Gregorian
#	calendar, dates on the Julian calendar or before the Common
#	Era may yield unexpected results. In particular, the year of
#	the Julian-to-Gregorian change may be up to three weeks short.
#	The era is not managed separately, so if the Common Era begins
#	(or the period Before the Common Era ends) with a partial week,
#	the few days at the beginning or end of the era may show up
#	as incorrectly belonging to the year zero.
#
#----------------------------------------------------------------------

proc ::tcl::clock::GetYearWeekDay { date 
				    { keys { iso8601Year iso8601Week dayOfWeek } } } {

    set daysInFirstWeek 4
    set firstDayOfWeek 1

    # Determine the calendar year of $j - $daysInFirstWeek + 1.
    # Compute an upper bound of the fiscal year as being one year
    # past the day on which the current week begins. Find the start
    # of that year.
    
    set j [dict get $date julianDay]
    set jd [expr { $j - $daysInFirstWeek + 1 }]
    set date1 [GetGregorianEraYearDay [dict create julianDay $jd]]
    switch -exact -- [dict get $date1 era] {
	BCE {
	    dict set date1 fiscalYear [expr { [dict get $date1 year] - 1}]
	}
	CE {
	    dict set date1 fiscalYear [expr { [dict get $date1 year] + 1}]
	}
    }
    dict unset date1 year
    dict unset date1 dayOfYear
    dict set date1 weekOfFiscalYear 1
    dict set date1 dayOfWeek $firstDayOfWeek

    set date1 [GetJulianDayFromEraYearWeekDay \
		   $date1[set date1 {}] \
		   $daysInFirstWeek \
		   $firstDayOfWeek \
		   { fiscalYear weekOfFiscalYear dayOfWeek }]
    set startOfFiscalYear [dict get $date1 julianDay]

    # If we guessed high, move one year earlier.
    
    if { $j < $startOfFiscalYear } {
	switch -exact -- [dict get $date1 era] {
	    BCE {
		dict incr date1 fiscalYear
	    }
	    CE {
		dict incr date1 fiscalYear -1
	    }
	}
	set date1 [GetJulianDayFromEraYearWeekDay \
		       $date1[set date1 {}] \
		       $daysInFirstWeek \
		       $firstDayOfWeek \
		       {fiscalYear weekOfFiscalYear dayOfWeek }]
	set startOfFiscalYear [dict get $date1 julianDay]
    }
    
    # Get the week number and the day within the week
    
    set fiscalYear [dict get $date1 fiscalYear]
    set dayOfFiscalYear [expr { $j - $startOfFiscalYear }]
    set weekOfFiscalYear [expr { ( $dayOfFiscalYear / 7 ) + 1 }]
    set dayOfWeek [expr { ( $dayOfFiscalYear + 1 ) % 7 }]
    if { $dayOfWeek < $firstDayOfWeek } {
	incr dayOfWeek 7
    }
    
    # Store the fiscal year, week, and day in the given slots in the
    # given dictionary.

    foreach key $keys \
	value [list $fiscalYear $weekOfFiscalYear $dayOfWeek] {
	    dict set date $key $value
	}

    return $date
}

#----------------------------------------------------------------------
#
# GetJulianDayFromEraYearWeekDay --
#
#	Finds the Julian Day Number corresponding to the given era,
#	year, week and day.







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







3871
3872
3873
3874
3875
3876
3877


























































































































































































































































































3878
3879
3880
3881
3882
3883
3884
	dict set date localeEra [lindex $etable $index 1]
	dict set date localeYear [expr { [dict get $date year] 
					 - [lindex $etable $index 2] }]
    }
    return $date

}



























































































































































































































































































#----------------------------------------------------------------------
#
# GetJulianDayFromEraYearWeekDay --
#
#	Finds the Julian Day Number corresponding to the given era,
#	year, week and day.
4404
4405
4406
4407
4408
4409
4410



4411
4412
4413
4414
4415
4416
4417
#		default is { iso8601Year iso8601Week dayOfWeek }.
#
# Results:
#	Returns the dictionary augmented with a 'julianDay' field
#	that gives the Julian Day Number corresponding to the given
#	date.
#



#----------------------------------------------------------------------

proc ::tcl::clock::GetJulianDayFromEraYearWeekDay {
    date 
    { daysInFirstWeek 4 } 
    { firstDayOfWeek 1 }
    { keys { iso8601Year iso8601Week dayOfWeek } }







>
>
>







3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
#		default is { iso8601Year iso8601Week dayOfWeek }.
#
# Results:
#	Returns the dictionary augmented with a 'julianDay' field
#	that gives the Julian Day Number corresponding to the given
#	date.
#
# Bugs:
#	This code needs to be moved to the C layer.
# 
#----------------------------------------------------------------------

proc ::tcl::clock::GetJulianDayFromEraYearWeekDay {
    date 
    { daysInFirstWeek 4 } 
    { firstDayOfWeek 1 }
    { keys { iso8601Year iso8601Week dayOfWeek } }
4463
4464
4465
4466
4467
4468
4469



4470
4471
4472
4473
4474
4475
4476
#	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.
#



#----------------------------------------------------------------------

proc ::tcl::clock::GetJulianDayFromEraYearMonthDay { date } {

    variable DaysInPriorMonthsInCommonYear
    variable DaysInPriorMonthsInLeapYear








>
>
>







3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
#	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::GetJulianDayFromEraYearMonthDay { date } {

    variable DaysInPriorMonthsInCommonYear
    variable DaysInPriorMonthsInLeapYear

4548
4549
4550
4551
4552
4553
4554



4555
4556
4557
4558
4559
4560
4561
#	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.
#



#----------------------------------------------------------------------

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

    # Get absolute year number from the civil year

    switch -exact -- [dict get $date era] {







>
>
>







4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
#	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 } {

    # Get absolute year number from the civil year

    switch -exact -- [dict get $date era] {
4605
4606
4607
4608
4609
4610
4611



4612
4613
4614
4615
4616
4617
4618
#
# Results:
#	Returns the given dictionary, augmented with a 'julianDay' key.
#
# Side effects:
#	None.
#



#----------------------------------------------------------------------

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

    # 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)







>
>
>







4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
#
# 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 } {

    # 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)
4855
4856
4857
4858
4859
4860
4861





4862
4863
4864
4865
4866
4867
4868
    } else {
	if { $gmt } {
	    set timezone :GMT
	}
    }

    EnterLocale $locale oldLocale






    set status [catch {

	foreach { quantity unit } $offsets {

	    switch -exact -- $unit {








>
>
>
>
>







4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
    } else {
	if { $gmt } {
	    set timezone :GMT
	}
    }

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

    set status [catch {

	foreach { quantity unit } $offsets {

	    switch -exact -- $unit {

4942
4943
4944
4945
4946
4947
4948



4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
#
#----------------------------------------------------------------------

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

    variable DaysInRomanMonthInCommonYear
    variable DaysInRomanMonthInLeapYear




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

    set date [GetMonthDay \
		  [GetGregorianEraYearDay \
		       [GetJulianDay \
			    [ConvertUTCToLocal \
				 [dict create seconds $clockval] \
				 $timezone]]]]
    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]







>
>
>



|
<
<
<
<
<







4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464





4465
4466
4467
4468
4469
4470
4471
#
#----------------------------------------------------------------------

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

    variable DaysInRomanMonthInCommonYear
    variable DaysInRomanMonthInLeapYear
    variable TZData

    set changeover [mc GREGORIAN_CHANGE_DATE]

    # 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]
4984
4985
4986
4987
4988
4989
4990
4991

4992
4993
4994
4995
4996
4997
4998

    set date [GetJulianDayFromEraYearMonthDay \
		  $date[set date {}]]
    dict set date localSeconds \
	[expr { -210866803200
		+ ( 86400 * wide([dict get $date julianDay]) )
		+ [dict get $date secondOfDay] }]
    set date [ConvertLocalToUTC $date[set date {}]]


    return [dict get $date seconds]

}

#----------------------------------------------------------------------
#







|
>







4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506

    set date [GetJulianDayFromEraYearMonthDay \
		  $date[set date {}]]
    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]

}

#----------------------------------------------------------------------
#
5013
5014
5015
5016
5017
5018
5019




5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040

5041
5042
5043
5044
5045
5046
5047
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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





    # Convert the time to Julian Day

    set date [GetJulianDay \
		  [ConvertUTCToLocal \
		       [dict create seconds $clockval] \
		       $timezone]]
    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 {}]]


    return [dict get $date seconds]

}

#----------------------------------------------------------------------
#







>
>
>
>


|
<
<
<














|
>







4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534



4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
# Side effects:
#	None.
#
#----------------------------------------------------------------------

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

    variable TZData

    set changeover [mc GREGORIAN_CHANGE_DATE]

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

}

#----------------------------------------------------------------------
#