Tcl Source Code

Check-in [39a21f437a]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:integrate branch clock-astronomical-jdn: merge pull request #16 from sebres/astronomical-jdn (https://github.com/sebres/tclclockmod/pull/16); astronomical and calendar JDN/JD with time fraction
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sebres-8-6-clock-speedup-cr2
Files: files | file ages | folders
SHA3-256: 39a21f437aeb2c3a6c364a785e3af1fadc6156390b4006ad7bc7621d5292453b
User & Date: sebres 2019-03-13 00:33:29
Context
2019-03-13
00:44
merge 8.6 check-in: 73e7e3f694 user: sebres tags: sebres-8-6-clock-speedup-cr2
00:33
integrate branch clock-astronomical-jdn: merge pull request #16 from sebres/astronomical-jdn (https:... check-in: 39a21f437a user: sebres tags: sebres-8-6-clock-speedup-cr2
00:24
scan: all JDN/JD are signed, so allow parse negative Julian days Closed-Leaf check-in: 7be9cada94 user: sebres tags: clock-astronomical-jdn
2019-03-05
22:58
merge 8.6 - timerate is part of Tcl now (since TIP#527 got merged), conflicts resolved, tclDate.c re... check-in: 3454e26373 user: sebres tags: sebres-8-6-clock-speedup-cr2
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to doc/clock.n.

394
395
396
397
398
399
400
401

402



403
404
405
406
407
408
409
...
546
547
548
549
550
551
552
























553
554
555
556
557
558
559
...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
.PP
The date is determined according to the fields that are present in the
preprocessed format string.  In order of preference:
.IP [1]
If the string contains a \fB%s\fR format group, representing
seconds from the epoch, that group is used to determine the date.
.IP [2]
If the string contains a \fB%J\fR format group, representing

the Julian Day Number, that group is used to determine the date.



.IP [3]
If the string contains a complete set of format groups specifying
century, year, month, and day of month; century, year, and day of year;
or ISO8601 fiscal year, week of year, and day of week; those groups are
combined and used to determine the date.  If more than one complete
set is present, the one at the rightmost position in the string is
used.
................................................................................
string of the same meaning in the locale, to indicate whether \fB%Y\fR refers
to years before or after Year 1 of the Common Era.  On input, accepts
the string \fBB.C.E.\fR, \fBB.C.\fR, \fBC.E.\fR, \fBA.D.\fR, or the
abbreviation appropriate to the current locale, and uses it to fix
whether \fB%Y\fR refers to years before or after Year 1 of the
Common Era.
.TP
























\fB%Es\fR
This affects similar to \fB%s\fR, but in opposition to \fB%s\fR it parses
or formats local seconds (not the posix seconds).
Because \fB%s\fR has the same precedence as \fB%s\fR (uniquely determines 
a point in time), it overrides all other input formats.
.TP
\fB%Ex\fR
................................................................................
(12-11) on a 12-hour clock.  On input, accepts such a number.
.TP
\fB%j\fR
On output, produces a three-digit number giving the day of the year
(001-366).  On input, accepts such a number.
.TP
\fB%J\fR
On output, produces a string of digits giving the Julian Day Number.
On input, accepts a string of digits and interprets it as a Julian Day Number.
The Julian Day Number is a count of the number of calendar days
that have elapsed since 1 January, 4713 BCE of the proleptic
Julian calendar.  The epoch time of 1 January 1970 corresponds
to Julian Day Number 2440588.
.TP
\fB%k\fR






|
>
|
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
.PP
The date is determined according to the fields that are present in the
preprocessed format string.  In order of preference:
.IP [1]
If the string contains a \fB%s\fR format group, representing
seconds from the epoch, that group is used to determine the date.
.IP [2]
If the string contains a \fB%J\fR, \fB%EJ\fR or \fB%Ej\fR format groups,
representing the Calendar or Astronomical Julian Day Number, that groups
are used to determine the date.
Note, that in case of \fB%EJ\fR or \fB%Ej\fR format groups, representing
the Julian Date with time fraction, this groups may be used to determine
the date and time.
.IP [3]
If the string contains a complete set of format groups specifying
century, year, month, and day of month; century, year, and day of year;
or ISO8601 fiscal year, week of year, and day of week; those groups are
combined and used to determine the date.  If more than one complete
set is present, the one at the rightmost position in the string is
used.
................................................................................
string of the same meaning in the locale, to indicate whether \fB%Y\fR refers
to years before or after Year 1 of the Common Era.  On input, accepts
the string \fBB.C.E.\fR, \fBB.C.\fR, \fBC.E.\fR, \fBA.D.\fR, or the
abbreviation appropriate to the current locale, and uses it to fix
whether \fB%Y\fR refers to years before or after Year 1 of the
Common Era.
.TP
\fB%Ej\fR
On output, produces a string of digits giving the Astronomical Julian Date or
Astronomical Julian Day Number (JDN/JD). In opposite to calendar julian day
\fB%J\fR, it starts the day at noon.
On input, accepts a string of digits (or floating point with the time fraction)
and interprets it as an Astronomical Julian Day Number (JDN/JD).
The Astronomical Julian Date is a count of the number of calendar days
that have elapsed since 1 January, 4713 BCE of the proleptic
Julian calendar, which contains also the time fraktion (after floating point).
The epoch time of 1 January 1970 corresponds to Astronomical JDN 2440587.5.
This value corresponds the julian day used in sqlite-database, and is the same
as result of \fBselect julianday(:seconds, 'unixepoch')\fR.
.TP
\fB%EJ\fR
On output, produces a string of digits giving the Calendar Julian Date.
In opposite to julian day \fB%J\fR format group, it produces float number.
In opposite to astronomical julian day \fB%Ej\fR group, it starts at midnight.
On input, accepts a string of digits (or floating point with the time fraction)
and interprets it as a Calendar Julian Day Number.
The Calendar Julian Date is a count of the number of calendar days
that have elapsed since 1 January, 4713 BCE of the proleptic
Julian calendar, which contains also the time fraktion (after floating point).
The epoch time of 1 January 1970 corresponds to Astronomical JDN 2440588.
.TP
\fB%Es\fR
This affects similar to \fB%s\fR, but in opposition to \fB%s\fR it parses
or formats local seconds (not the posix seconds).
Because \fB%s\fR has the same precedence as \fB%s\fR (uniquely determines 
a point in time), it overrides all other input formats.
.TP
\fB%Ex\fR
................................................................................
(12-11) on a 12-hour clock.  On input, accepts such a number.
.TP
\fB%j\fR
On output, produces a three-digit number giving the day of the year
(001-366).  On input, accepts such a number.
.TP
\fB%J\fR
On output, produces a string of digits giving the calendar Julian Day Number.
On input, accepts a string of digits and interprets it as a Julian Day Number.
The Julian Day Number is a count of the number of calendar days
that have elapsed since 1 January, 4713 BCE of the proleptic
Julian calendar.  The epoch time of 1 January 1970 corresponds
to Julian Day Number 2440588.
.TP
\fB%k\fR

Changes to generic/tclClock.c.

231
232
233
234
235
236
237
238

239
240
241
242
243
244
245
....
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
....
3715
3716
3717
3718
3719
3720
3721
3722


3723
3724
3725
3726
3727
3728
3729
3730
    data->mcLitIdxs = NULL;
    data->mcDicts = NULL;
    data->lastTZEpoch = 0;
    data->currentYearCentury = ClockDefaultYearCentury;
    data->yearOfCenturySwitch = ClockDefaultCenturySwitch;
    data->validMinYear = INT_MIN;
    data->validMaxYear = INT_MAX;
    data->maxJulianDay = 5373484; /* corresponds 9999-12-31 23:59:59 per default */


    data->systemTimeZone = NULL;
    data->systemSetupTZData = NULL;
    data->gmtSetupTimeZoneUnnorm = NULL;
    data->gmtSetupTimeZone = NULL;
    data->gmtSetupTZData = NULL;
    data->gmtTZName = NULL;
................................................................................
	    if (i+1 >= objc) {
		Tcl_SetObjResult(interp,
		    Tcl_NewIntObj(dataPtr->validMaxYear));
	    }
	break;
	case CLOCK_MAX_JDN:
	    if (i < objc) {
		Tcl_WideInt jd;
		if (TclGetWideIntFromObj(interp, objv[i], &jd) != TCL_OK) {
		    return TCL_ERROR;
		}
		dataPtr->maxJulianDay = jd;
		Tcl_SetObjResult(interp, objv[i]);
		continue;
	    }
	    if (i+1 >= objc) {
		Tcl_SetObjResult(interp,
		    Tcl_NewWideIntObj(dataPtr->maxJulianDay));
	    }
	break;
	case CLOCK_VALIDATE:
	    if (i < objc) {
		int val;
		if (Tcl_GetBooleanFromObj(interp, objv[i], &val) != TCL_OK) {
		    return TCL_ERROR;
................................................................................
	}
	info->flags |= CLF_ASSEMBLE_SECONDS;
	info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
    }

    /* some overflow checks */
    if (info->flags & CLF_JULIANDAY) {
    	ClockClientData *dataPtr = opts->clientData;


    	if (yydate.julianDay > dataPtr->maxJulianDay) {
	    Tcl_SetObjResult(opts->interp, Tcl_NewStringObj(
		"requested date too large to represent", -1));
	    Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL);
	    return TCL_ERROR;
	}
    }







|
>







 







|
|


|





|







 







|
>
>
|







231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
....
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
....
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
    data->mcLitIdxs = NULL;
    data->mcDicts = NULL;
    data->lastTZEpoch = 0;
    data->currentYearCentury = ClockDefaultYearCentury;
    data->yearOfCenturySwitch = ClockDefaultCenturySwitch;
    data->validMinYear = INT_MIN;
    data->validMaxYear = INT_MAX;
    /* corresponds max of JDN in sqlite - 9999-12-31 23:59:59 per default */
    data->maxJDN = 5373484.499999994; 

    data->systemTimeZone = NULL;
    data->systemSetupTZData = NULL;
    data->gmtSetupTimeZoneUnnorm = NULL;
    data->gmtSetupTimeZone = NULL;
    data->gmtSetupTZData = NULL;
    data->gmtTZName = NULL;
................................................................................
	    if (i+1 >= objc) {
		Tcl_SetObjResult(interp,
		    Tcl_NewIntObj(dataPtr->validMaxYear));
	    }
	break;
	case CLOCK_MAX_JDN:
	    if (i < objc) {
		double jd;
		if (Tcl_GetDoubleFromObj(interp, objv[i], &jd) != TCL_OK) {
		    return TCL_ERROR;
		}
		dataPtr->maxJDN = jd;
		Tcl_SetObjResult(interp, objv[i]);
		continue;
	    }
	    if (i+1 >= objc) {
		Tcl_SetObjResult(interp,
		    Tcl_NewDoubleObj(dataPtr->maxJDN));
	    }
	break;
	case CLOCK_VALIDATE:
	    if (i < objc) {
		int val;
		if (Tcl_GetBooleanFromObj(interp, objv[i], &val) != TCL_OK) {
		    return TCL_ERROR;
................................................................................
	}
	info->flags |= CLF_ASSEMBLE_SECONDS;
	info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
    }

    /* some overflow checks */
    if (info->flags & CLF_JULIANDAY) {
	ClockClientData *dataPtr = opts->clientData;
	double curJDN = (double)yydate.julianDay
	    + ((double)yySecondOfDay - SECONDS_PER_DAY/2) / SECONDS_PER_DAY;
	if (curJDN > dataPtr->maxJDN) {
	    Tcl_SetObjResult(opts->interp, Tcl_NewStringObj(
		"requested date too large to represent", -1));
	    Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL);
	    return TCL_ERROR;
	}
    }

Changes to generic/tclClockFmt.c.

1578
1579
1580
1581
1582
1583
1584


































































1585
1586
1587
1588
1589
1590
1591
....
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
....
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822






1823
1824
1825
1826
1827
1828
1829
....
2320
2321
2322
2323
2324
2325
2326

2327
2328
2329
2330
2331
2332
2333
....
2587
2588
2589
2590
2591
2592
2593





























































2594
2595
2596
2597
2598
2599
2600
....
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834






2835
2836
2837
2838
2839
2840
2841
    if (tok->map->offs > 0) {
	*(int *)(((char *)info) + tok->map->offs) = --val;
    }

    return TCL_OK;
}


































































 
static int
ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts,
    DateInfo *info, ClockScanToken *tok)
{
    int minLen, maxLen;
    int len = 0;
................................................................................
    /* %S */
    {CTOKT_INT, CLF_TIME, 0, 1, 2, TclOffset(DateInfo, date.secondOfMin),
	NULL},
    /* %p %P */
    {CTOKT_PARSER, 0, 0, 0, 0xffff, 0,
	ClockScnToken_amPmInd_Proc, NULL},
    /* %J */
    {CTOKT_WIDE, CLF_JULIANDAY, 0, 1, 0xffff, TclOffset(DateInfo, date.julianDay),
	NULL},
    /* %j */
    {CTOKT_INT, CLF_DAYOFYEAR, 0, 1, 3, TclOffset(DateInfo, date.dayOfYear),
	NULL},
    /* %C */
    {CTOKT_INT, CLF_CENTURY|CLF_ISO8601CENTURY, 0, 1, 2, TclOffset(DateInfo, dateCentury),
	NULL},
................................................................................
};
static const char *ScnSTokenMapAliasIndex[2] = {
    "eNBhkIlPAuwZW",
    "dmbbHHHpaaazU"
};

static const char *ScnETokenMapIndex =
    "Eys";
static ClockScanTokenMap ScnETokenMap[] = {
    /* %EE */
    {CTOKT_PARSER, 0, 0, 0, 0xffff, TclOffset(DateInfo, date.year),
	ClockScnToken_LocaleERA_Proc, (void *)MCLIT_LOCALE_NUMERALS},






    /* %Ey */
    {CTOKT_PARSER, 0, 0, 0, 0xffff, 0, /* currently no capture, parse only token */
	ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
    /* %Es */
    {CTOKT_WIDE, CLF_LOCALSEC | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.localSeconds),
	NULL},
};
................................................................................
	}
	tok++;
    }

    /*
     * Invalidate result
     */


    /* seconds token (%s) take precedence over all other tokens */
    if ((opts->flags & CLF_EXTENDED) || !(flags & CLF_POSIXSEC)) {
	if (flags & CLF_DATE) {

	    if (!(flags & CLF_JULIANDAY)) {
		info->flags |= CLF_ASSEMBLE_SECONDS|CLF_ASSEMBLE_JULIANDAY;
................................................................................
	    dow = 0;
	}
	dow++;
    }
    *val = ( dateFmt->date.dayOfYear - dow + 7 ) / 7;
    return TCL_OK;
}





























































static int
ClockFmtToken_TimeZone_Proc(
    ClockFmtScnCmdArgs *opts,
    DateFormat *dateFmt,
    ClockFormatToken *tok,
    int *val)
{
................................................................................
};
static const char *FmtSTokenMapAliasIndex[2] = {
    "hPWZ",
    "bpUz"
};

static const char *FmtETokenMapIndex =
    "Eys";
static ClockFormatTokenMap FmtETokenMap[] = {
    /* %EE */
    {CFMTT_PROC, NULL, 0, 0, 0, 0, 0,
	ClockFmtToken_LocaleERA_Proc, NULL},






    /* %Ey %EC */
    {CTOKT_INT, NULL, 0, 0, 0, 0, TclOffset(DateFormat, date.year),
	ClockFmtToken_LocaleERAYear_Proc, NULL},
    /* %Es */
    {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.localSeconds), NULL},
};
static const char *FmtETokenMapAliasIndex[2] = {






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|




>
>
>
>
>
>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|




>
>
>
>
>
>







1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
....
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
....
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
....
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
....
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
....
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
    if (tok->map->offs > 0) {
	*(int *)(((char *)info) + tok->map->offs) = --val;
    }

    return TCL_OK;
}
 
static int
ClockScnToken_JDN_Proc(ClockFmtScnCmdArgs *opts,
    DateInfo *info, ClockScanToken *tok)
{
    int minLen, maxLen;
    register const char *p = yyInput, *end; const char *s;
    Tcl_WideInt intJD; int fractJD = 0, fractJDDiv = 1;

    DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);

    end = yyInput + maxLen;

    /* currently positive astronomic dates only */
    if (*p == '+' || *p == '-') { p++; };
    s = p;
    while (p < end && isdigit(UCHAR(*p))) {
	p++;
    }
    if ( _str2wideInt(&intJD, s, p, (*yyInput != '-' ? 1 : -1)) != TCL_OK) {
	return TCL_RETURN;
    };
    yyInput = p;
    if (p >= end || *p++ != '.') { /* allow pure integer JDN */
	/* by astronomical JD the seconds of day offs is 12 hours */
	if (tok->map->offs) {
	    goto done;
	}
	/* calendar JD */
	yydate.julianDay = intJD;
	return TCL_OK;
    }
    s = p;
    while (p < end && isdigit(UCHAR(*p))) {
    	fractJDDiv *= 10;
	p++;
    }
    if ( _str2int(&fractJD, s, p, 1) != TCL_OK) {
	return TCL_RETURN;
    };
    yyInput = p;

done:
    /* 
     * Build a date from julian day (integer and fraction).
     * Note, astronomical JDN starts at noon in opposite to calendar julianday.
     */

    fractJD = (int)tok->map->offs /* 0 for calendar or 43200 for astro JD */
	+ (int)((Tcl_WideInt)SECONDS_PER_DAY * fractJD / fractJDDiv);
    if (fractJD > SECONDS_PER_DAY) {
	fractJD %= SECONDS_PER_DAY;
	intJD += 1;
    }
    yydate.secondOfDay = fractJD;
    yydate.julianDay = intJD;

    yydate.seconds =
	-210866803200L
	+ ( SECONDS_PER_DAY * intJD )
	+ ( fractJD );

    info->flags |= CLF_POSIXSEC;

    return TCL_OK;
}
 
static int
ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts,
    DateInfo *info, ClockScanToken *tok)
{
    int minLen, maxLen;
    int len = 0;
................................................................................
    /* %S */
    {CTOKT_INT, CLF_TIME, 0, 1, 2, TclOffset(DateInfo, date.secondOfMin),
	NULL},
    /* %p %P */
    {CTOKT_PARSER, 0, 0, 0, 0xffff, 0,
	ClockScnToken_amPmInd_Proc, NULL},
    /* %J */
    {CTOKT_WIDE, CLF_JULIANDAY | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.julianDay),
	NULL},
    /* %j */
    {CTOKT_INT, CLF_DAYOFYEAR, 0, 1, 3, TclOffset(DateInfo, date.dayOfYear),
	NULL},
    /* %C */
    {CTOKT_INT, CLF_CENTURY|CLF_ISO8601CENTURY, 0, 1, 2, TclOffset(DateInfo, dateCentury),
	NULL},
................................................................................
};
static const char *ScnSTokenMapAliasIndex[2] = {
    "eNBhkIlPAuwZW",
    "dmbbHHHpaaazU"
};

static const char *ScnETokenMapIndex =
    "EJjys";
static ClockScanTokenMap ScnETokenMap[] = {
    /* %EE */
    {CTOKT_PARSER, 0, 0, 0, 0xffff, TclOffset(DateInfo, date.year),
	ClockScnToken_LocaleERA_Proc, (void *)MCLIT_LOCALE_NUMERALS},
    /* %EJ */
    {CTOKT_PARSER, CLF_JULIANDAY | CLF_SIGNED, 0, 1, 0xffff, 0, /* calendar JDN starts at midnight */
	ClockScnToken_JDN_Proc, NULL},
    /* %Ej */
    {CTOKT_PARSER, CLF_JULIANDAY | CLF_SIGNED, 0, 1, 0xffff, (SECONDS_PER_DAY/2), /* astro JDN starts at noon */
	ClockScnToken_JDN_Proc, NULL},
    /* %Ey */
    {CTOKT_PARSER, 0, 0, 0, 0xffff, 0, /* currently no capture, parse only token */
	ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
    /* %Es */
    {CTOKT_WIDE, CLF_LOCALSEC | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.localSeconds),
	NULL},
};
................................................................................
	}
	tok++;
    }

    /*
     * Invalidate result
     */
    flags |= info->flags;

    /* seconds token (%s) take precedence over all other tokens */
    if ((opts->flags & CLF_EXTENDED) || !(flags & CLF_POSIXSEC)) {
	if (flags & CLF_DATE) {

	    if (!(flags & CLF_JULIANDAY)) {
		info->flags |= CLF_ASSEMBLE_SECONDS|CLF_ASSEMBLE_JULIANDAY;
................................................................................
	    dow = 0;
	}
	dow++;
    }
    *val = ( dateFmt->date.dayOfYear - dow + 7 ) / 7;
    return TCL_OK;
}
static int
ClockFmtToken_JDN_Proc(
    ClockFmtScnCmdArgs *opts,
    DateFormat *dateFmt,
    ClockFormatToken *tok,
    int *val)
 {
    Tcl_WideInt intJD = dateFmt->date.julianDay;
    int fractJD;

    /* Convert to JDN parts (regarding start offset) and time fraction */
    fractJD = dateFmt->date.secondOfDay 
	- (int)tok->map->offs; /* 0 for calendar or 43200 for astro JD */
    if (fractJD < 0) {
    	intJD--;
	fractJD += SECONDS_PER_DAY;
    }
    if (fractJD && intJD < 0) { /* avoid jump over 0, by negative JD's */
	intJD++;
	if (intJD == 0) {
	    /* -0.0 / -0.9 has zero integer part, so append "-" extra */
	    if (FrmResultAllocate(dateFmt, 1) != TCL_OK) { return TCL_ERROR; };
	    *dateFmt->output++ = '-';
	}
	/* and inverse seconds of day, -0(75) -> -0.25 as float */
	fractJD = SECONDS_PER_DAY - fractJD;
    }

    /* 21 is max width of (negative) wide-int (rather smaller, but anyway a time fraction below) */
    if (FrmResultAllocate(dateFmt, 21) != TCL_OK) { return TCL_ERROR; };
    dateFmt->output = _witoaw(dateFmt->output, intJD, '0', 1);
    /* simplest cases .0 and .5 */
    if (!fractJD || fractJD == (SECONDS_PER_DAY / 2)) {
	/* point + 0 or 5 */
	if (FrmResultAllocate(dateFmt, 1+1) != TCL_OK) { return TCL_ERROR; };
	*dateFmt->output++ = '.';
	*dateFmt->output++ = !fractJD ? '0' : '5';
	*dateFmt->output = '\0';
	return TCL_OK;
    } else {
	/* wrap the time fraction */
	#define JDN_MAX_PRECISION 8
	#define JDN_MAX_PRECBOUND 100000000 /* 10**JDN_MAX_PRECISION */
	char *p;

	/* to float (part after floating point, + 0.5 to round it up) */
	fractJD = (int)(
	    (double)fractJD * JDN_MAX_PRECBOUND / SECONDS_PER_DAY + 0.5
	);
	/* point + integer (as time fraction after floating point) */
	if (FrmResultAllocate(dateFmt, 1+JDN_MAX_PRECISION) != TCL_OK) { return TCL_ERROR; };
	*dateFmt->output++ = '.';
	p = _itoaw(dateFmt->output, fractJD, '0', JDN_MAX_PRECISION);
	/* remove trailing zero's */
	dateFmt->output++;
	while (p > dateFmt->output && *(p-1) == '0') {p--;}
	*p = '\0';
	dateFmt->output = p;
    }
    return TCL_OK;
}
static int
ClockFmtToken_TimeZone_Proc(
    ClockFmtScnCmdArgs *opts,
    DateFormat *dateFmt,
    ClockFormatToken *tok,
    int *val)
{
................................................................................
};
static const char *FmtSTokenMapAliasIndex[2] = {
    "hPWZ",
    "bpUz"
};

static const char *FmtETokenMapIndex =
    "EJjys";
static ClockFormatTokenMap FmtETokenMap[] = {
    /* %EE */
    {CFMTT_PROC, NULL, 0, 0, 0, 0, 0,
	ClockFmtToken_LocaleERA_Proc, NULL},
    /* %EJ */
    {CFMTT_PROC, NULL, 0, 0, 0, 0, 0, /* calendar JDN starts at midnight */
	ClockFmtToken_JDN_Proc, NULL},
    /* %Ej */
    {CFMTT_PROC, NULL, 0, 0, 0, 0, (SECONDS_PER_DAY/2), /* astro JDN starts at noon */
	ClockFmtToken_JDN_Proc, NULL},
    /* %Ey %EC */
    {CTOKT_INT, NULL, 0, 0, 0, 0, TclOffset(DateFormat, date.year),
	ClockFmtToken_LocaleERAYear_Proc, NULL},
    /* %Es */
    {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.localSeconds), NULL},
};
static const char *FmtETokenMapAliasIndex[2] = {

Changes to generic/tclDate.h.

306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
    /* Cache for current clock parameters, imparted via "configure" */
    size_t lastTZEpoch;
    int currentYearCentury;
    int yearOfCenturySwitch;
    int validMinYear;
    int validMaxYear;
    Tcl_WideInt maxJulianDay;

    Tcl_Obj *systemTimeZone;
    Tcl_Obj *systemSetupTZData;
    Tcl_Obj *gmtSetupTimeZoneUnnorm;
    Tcl_Obj *gmtSetupTimeZone;
    Tcl_Obj *gmtSetupTZData;
    Tcl_Obj *gmtTZName;






|







306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
    /* Cache for current clock parameters, imparted via "configure" */
    size_t lastTZEpoch;
    int currentYearCentury;
    int yearOfCenturySwitch;
    int validMinYear;
    int validMaxYear;
    double maxJDN;

    Tcl_Obj *systemTimeZone;
    Tcl_Obj *systemSetupTZData;
    Tcl_Obj *gmtSetupTimeZoneUnnorm;
    Tcl_Obj *gmtSetupTimeZone;
    Tcl_Obj *gmtSetupTZData;
    Tcl_Obj *gmtTZName;

Changes to tests/clock.test.

15354
15355
15356
15357
15358
15359
15360
15361
15362
15363
15364
15365
15366
15367
15368
15369
15370
15371
15372
15373
15374
15375
15376
15377
15378
15379
15380
15381
15382
15383
15384
15385
15386
15387
15388
15389
15390
15391
15392
15393
15394
15395
15396
15397
15398
15399
15400
15401
15402
15403
15404
15405
15406
15407
15408
15409
15410
15411
15412
15413
15414
15415
15416
15417
15418
15419
15420
15421
15422
15423
15424
15425
15426
15427
15428
15429
15430
15431
15432
15433
15434
15435
15436
15437
15438
15439
15440
15441
15442
.....
18895
18896
18897
18898
18899
18900
18901





















































































18902
18903
18904
18905
18906
18907
18908
.....
21306
21307
21308
21309
21310
21311
21312
21313

21314

21315











21316
21317
21318
21319
21320
21321
21322
test clock-4.96 { format time of day 23:59:59 } {
    clock format 86399 \
        -format {%H %OH %I %OI %k %Ok %l %Ol %M %OM %p %P %r %R %S %OS %T %X %EX %+} \
	  -locale en_US_roman \
        -gmt true
} {23 xxiii 11 xi 23 xxiii 11 xi 59 lix PM pm 11:59:59 pm 23:59 59 lix 23:59:59 23:59:59 xxiii h lix m lix s Thu Jan  1 23:59:59 GMT 1970}

test clock-4.97.1 { format julian day } {
    clock format 0 -format {%J} -gmt true
} {2440588}
test clock-4.97.2 { format julian day } {
    clock format 43200 -format {%J} -gmt true
} {2440588}
test clock-4.97.3 { format julian day } {
    clock format 86399 -format {%J} -gmt true
} {2440588}
test clock-4.97.4 { format julian day } {
    clock format 86400 -format {%J} -gmt true
} {2440589}
test clock-4.97.5 { format julian day } {
    clock format 129599 -format {%J} -gmt true
} {2440589}
test clock-4.97.6 { format julian day } {
    clock format 129600 -format {%J} -gmt true
} {2440589}
test clock-4.97.7 { format julian day } {
    set i 1548249092
    list \
	[clock format $i -format {%J} -gmt true] \
	[clock format [incr i] -format {%J} -gmt true] \
	[clock format [incr i] -format {%J} -gmt true]
} {2458507 2458507 2458507}
test clock-4.97.8 { format julian day } {
    set res {}
    foreach i {
	-172800 -129600 -86400 -43200
	-1 0 1 21600 43199 43200 86399 
	86400 86401 108000 129600 172800
    } {
	lappend res $i [clock format [expr -210866803200 - $i] \
	    -format {%EE %Y-%m-%d %T -- %J} -gmt true]
    }
    set res
} [list \
   -172800 {B.C.E. 4713-01-03 00:00:00 -- 0000002} \
   -129600 {B.C.E. 4713-01-02 12:00:00 -- 0000001} \
    -86400 {B.C.E. 4713-01-02 00:00:00 -- 0000001} \
    -43200 {B.C.E. 4713-01-01 12:00:00 -- 0000000} \
        -1 {B.C.E. 4713-01-01 00:00:01 -- 0000000} \
         0 {B.C.E. 4713-01-01 00:00:00 -- 0000000} \
         1 {B.C.E. 4714-12-31 23:59:59 -- -000001} \
     21600 {B.C.E. 4714-12-31 18:00:00 -- -000001} \
     43199 {B.C.E. 4714-12-31 12:00:01 -- -000001} \
     43200 {B.C.E. 4714-12-31 12:00:00 -- -000001} \
     86399 {B.C.E. 4714-12-31 00:00:01 -- -000001} \
     86400 {B.C.E. 4714-12-31 00:00:00 -- -000001} \
     86401 {B.C.E. 4714-12-30 23:59:59 -- -000002} \
    108000 {B.C.E. 4714-12-30 18:00:00 -- -000002} \
    129600 {B.C.E. 4714-12-30 12:00:00 -- -000002} \
    172800 {B.C.E. 4714-12-30 00:00:00 -- -000002} \
]
test clock-4.97.9 { format JDN/JD (calendar and astronomical) } {
    set res {}
    foreach i {
	-86400 -43200
	-1 0 1 
	43199 43200 43201 86400
    } {
	lappend res $i [clock format [expr 653133196800 + $i] \
	    -format {%Y-%m-%d %T -- %J} -gmt true]
    }
    set res
} [list \
    -86400 {22666-12-19 00:00:00 -- 9999999} \
    -43200 {22666-12-19 12:00:00 -- 9999999} \
        -1 {22666-12-19 23:59:59 -- 9999999} \
         0 {22666-12-20 00:00:00 -- 10000000} \
         1 {22666-12-20 00:00:01 -- 10000000} \
     43199 {22666-12-20 11:59:59 -- 10000000} \
     43200 {22666-12-20 12:00:00 -- 10000000} \
     43201 {22666-12-20 12:00:01 -- 10000000} \
     86400 {22666-12-21 00:00:00 -- 10000001} \
]

# END testcases4

# BEGIN testcases5

# Test formatting of Daylight Saving Time
................................................................................
	[clock scan {86400 2440588} -format {%s %J} -gmt true] \
	[clock scan {0 2440589} -format {%s %J} -gmt true]
} {86400 0 86400 0}

test clock-7.9 {Julian Day, two values} {
    clock scan {2440588 2440589} -format {%J %J} -gmt true
} 86400






















































































# BEGIN testcases8

# Test parsing of ccyymmdd

test clock-8.1 {parse ccyymmdd} {
    clock scan {1970 Jan 02} -format {%C%y %b %d} -locale en_US_roman -gmt 1
................................................................................
} 1009756800
# END testcases8

test clock-9.1 {seconds take precedence over ccyymmdd} {
    clock scan {0 20000101} -format {%s %Y%m%d} -gmt true
} 0

test clock-9.2 {Julian day takes precedence over ccyymmdd} {

    clock scan {2440588 20000101} -format {%J %Y%m%d} -gmt true

} 0












# Test parsing of ccyyddd

test clock-10.1 {parse ccyyddd} {
    clock scan {1970 001} -format {%Y %j} -locale en_US_roman -gmt 1
} 0
test clock-10.2 {parse ccyyddd} {






|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|







|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|









|



|
|
|
|
|
|
|
|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>







15354
15355
15356
15357
15358
15359
15360
15361
15362
15363
15364
15365
15366
15367
15368
15369
15370
15371
15372
15373
15374
15375
15376
15377
15378
15379
15380
15381
15382
15383
15384
15385
15386
15387
15388
15389
15390
15391
15392
15393
15394
15395
15396
15397
15398
15399
15400
15401
15402
15403
15404
15405
15406
15407
15408
15409
15410
15411
15412
15413
15414
15415
15416
15417
15418
15419
15420
15421
15422
15423
15424
15425
15426
15427
15428
15429
15430
15431
15432
15433
15434
15435
15436
15437
15438
15439
15440
15441
15442
.....
18895
18896
18897
18898
18899
18900
18901
18902
18903
18904
18905
18906
18907
18908
18909
18910
18911
18912
18913
18914
18915
18916
18917
18918
18919
18920
18921
18922
18923
18924
18925
18926
18927
18928
18929
18930
18931
18932
18933
18934
18935
18936
18937
18938
18939
18940
18941
18942
18943
18944
18945
18946
18947
18948
18949
18950
18951
18952
18953
18954
18955
18956
18957
18958
18959
18960
18961
18962
18963
18964
18965
18966
18967
18968
18969
18970
18971
18972
18973
18974
18975
18976
18977
18978
18979
18980
18981
18982
18983
18984
18985
18986
18987
18988
18989
18990
18991
18992
18993
.....
21391
21392
21393
21394
21395
21396
21397
21398
21399
21400
21401
21402
21403
21404
21405
21406
21407
21408
21409
21410
21411
21412
21413
21414
21415
21416
21417
21418
21419
21420
test clock-4.96 { format time of day 23:59:59 } {
    clock format 86399 \
        -format {%H %OH %I %OI %k %Ok %l %Ol %M %OM %p %P %r %R %S %OS %T %X %EX %+} \
	  -locale en_US_roman \
        -gmt true
} {23 xxiii 11 xi 23 xxiii 11 xi 59 lix PM pm 11:59:59 pm 23:59 59 lix 23:59:59 23:59:59 xxiii h lix m lix s Thu Jan  1 23:59:59 GMT 1970}

test clock-4.97.1 { format JDN/JD (calendar and astronomical) } {
    clock format 0 -format {%J %EJ %Ej} -gmt true
} {2440588 2440588.0 2440587.5}
test clock-4.97.2 { format JDN/JD (calendar and astronomical) } {
    clock format 43200 -format {%J %EJ %Ej} -gmt true
} {2440588 2440588.5 2440588.0}
test clock-4.97.3 { format JDN/JD (calendar and astronomical) } {
    clock format 86399 -format {%J %EJ %Ej} -gmt true
} {2440588 2440588.99998843 2440588.49998843}
test clock-4.97.4 { format JDN/JD (calendar and astronomical) } {
    clock format 86400 -format {%J %EJ %Ej} -gmt true
} {2440589 2440589.0 2440588.5}
test clock-4.97.5 { format JDN/JD (calendar and astronomical) } {
    clock format 129599 -format {%J %EJ %Ej} -gmt true
} {2440589 2440589.49998843 2440588.99998843}
test clock-4.97.6 { format JDN/JD (calendar and astronomical) } {
    clock format 129600 -format {%J %EJ %Ej} -gmt true
} {2440589 2440589.5 2440589.0}
test clock-4.97.7 { format JDN/JD (calendar and astronomical) } {
    set i 1548249092
    list \
	[clock format $i -format {%J %EJ %Ej} -gmt true] \
	[clock format [incr i] -format {%J %EJ %Ej} -gmt true] \
	[clock format [incr i] -format {%J %EJ %Ej} -gmt true]
} {{2458507 2458507.54967593 2458507.04967593} {2458507 2458507.5496875 2458507.0496875} {2458507 2458507.54969907 2458507.04969907}}
test clock-4.97.8 { format JDN/JD (calendar and astronomical) } {
    set res {}
    foreach i {
	-172800 -129600 -86400 -43200
	-1 0 1 21600 43199 43200 86399 
	86400 86401 108000 129600 172800
    } {
	lappend res $i [clock format [expr -210866803200 - $i] \
	    -format {%EE %Y-%m-%d %T -- %J %EJ %Ej} -gmt true]
    }
    set res
} [list \
   -172800 {B.C.E. 4713-01-03 00:00:00 -- 0000002 2.0 1.5} \
   -129600 {B.C.E. 4713-01-02 12:00:00 -- 0000001 1.5 1.0} \
    -86400 {B.C.E. 4713-01-02 00:00:00 -- 0000001 1.0 0.5} \
    -43200 {B.C.E. 4713-01-01 12:00:00 -- 0000000 0.5 0.0} \
        -1 {B.C.E. 4713-01-01 00:00:01 -- 0000000 0.00001157 -0.49998843} \
         0 {B.C.E. 4713-01-01 00:00:00 -- 0000000 0.0 -0.5} \
         1 {B.C.E. 4714-12-31 23:59:59 -- -000001 -0.00001157 -0.50001157} \
     21600 {B.C.E. 4714-12-31 18:00:00 -- -000001 -0.25 -0.75} \
     43199 {B.C.E. 4714-12-31 12:00:01 -- -000001 -0.49998843 -0.99998843} \
     43200 {B.C.E. 4714-12-31 12:00:00 -- -000001 -0.5 -1.0} \
     86399 {B.C.E. 4714-12-31 00:00:01 -- -000001 -0.99998843 -1.49998843} \
     86400 {B.C.E. 4714-12-31 00:00:00 -- -000001 -1.0 -1.5} \
     86401 {B.C.E. 4714-12-30 23:59:59 -- -000002 -1.00001157 -1.50001157} \
    108000 {B.C.E. 4714-12-30 18:00:00 -- -000002 -1.25 -1.75} \
    129600 {B.C.E. 4714-12-30 12:00:00 -- -000002 -1.5 -2.0} \
    172800 {B.C.E. 4714-12-30 00:00:00 -- -000002 -2.0 -2.5} \
]
test clock-4.97.9 { format JDN/JD (calendar and astronomical) } {
    set res {}
    foreach i {
	-86400 -43200
	-1 0 1 
	43199 43200 43201 86400
    } {
	lappend res $i [clock format [expr 653133196800 + $i] \
	    -format {%Y-%m-%d %T -- %J %EJ %Ej} -gmt true]
    }
    set res
} [list \
    -86400 {22666-12-19 00:00:00 -- 9999999 9999999.0 9999998.5} \
    -43200 {22666-12-19 12:00:00 -- 9999999 9999999.5 9999999.0} \
        -1 {22666-12-19 23:59:59 -- 9999999 9999999.99998843 9999999.49998843} \
         0 {22666-12-20 00:00:00 -- 10000000 10000000.0 9999999.5} \
         1 {22666-12-20 00:00:01 -- 10000000 10000000.00001157 9999999.50001157} \
     43199 {22666-12-20 11:59:59 -- 10000000 10000000.49998843 9999999.99998843} \
     43200 {22666-12-20 12:00:00 -- 10000000 10000000.5 10000000.0} \
     43201 {22666-12-20 12:00:01 -- 10000000 10000000.50001157 10000000.00001157} \
     86400 {22666-12-21 00:00:00 -- 10000001 10000001.0 10000000.5} \
]

# END testcases4

# BEGIN testcases5

# Test formatting of Daylight Saving Time
................................................................................
	[clock scan {86400 2440588} -format {%s %J} -gmt true] \
	[clock scan {0 2440589} -format {%s %J} -gmt true]
} {86400 0 86400 0}

test clock-7.9 {Julian Day, two values} {
    clock scan {2440588 2440589} -format {%J %J} -gmt true
} 86400
test clock-7.10 {Calendar vs Astronomical Julian Day (without and with time fraction)} {
    list \
	[clock scan {2440588}   -format {%J}  -gmt true] \
	[clock scan {2440588}   -format {%EJ} -gmt true] \
	[clock scan {2440588}   -format {%Ej} -gmt true] \
	[clock scan {2440588.5} -format {%EJ} -gmt true] \
	[clock scan {2440588.5} -format {%Ej} -gmt true] \
} {0 0 43200 43200 86400}


test clock-7.11 {Astronomical JDN/JD} {
    clock scan 0 -format %Ej -gmt true
} -210866760000

test clock-7.12 {Astronomical JDN/JD} {
    clock format [clock scan 2440587.5 -format %Ej -gmt true] \
	-format "%Y-%m-%d %T" -gmt true
} "1970-01-01 00:00:00"

test clock-7.13 {Astronomical JDN/JD} {
    clock format [clock scan 2451544.5 -format %Ej -gmt true] \
	-format "%Y-%m-%d %T" -gmt true
} "2000-01-01 00:00:00"

test clock-7.13.1 {Astronomical JDN/JD} {
    clock format [clock scan 2488069.5 -format %Ej -gmt true] \
	-format "%Y-%m-%d %T" -gmt true
} "2100-01-01 00:00:00"

test clock-7.14 {Astronomical JDN/JD} {
    clock format [clock scan 5373483.5 -format %Ej -gmt true] \
	-format "%Y-%m-%d %T" -gmt true
} "9999-12-31 00:00:00"

test clock-7.14.1 {Astronomical JDN/JD} {
    clock format [clock scan 5373484 -format %Ej -gmt true] \
	-format "%Y-%m-%d %T" -gmt true
} "9999-12-31 12:00:00"
test clock-7.14.2 {Astronomical JDN/JD} {
    clock format [clock scan 5373484.49999 -format %Ej -gmt true] \
	-format "%Y-%m-%d %T" -gmt true
} "9999-12-31 23:59:59"

test clock-7.15 {Astronomical JDN/JD, bad} {
    list [catch {
	clock scan bogus -format %Ej
    } result] $result $errorCode
} {1 {input string does not match supplied format} {CLOCK badInputString}}

test clock-7.16 {Astronomical JDN/JD, overflow} {
    list [catch {
	clock scan 5373484.5 -format %Ej
    } result] $result $errorCode \
    [catch {
	clock scan 5373485 -format %Ej
    } result] $result $errorCode \
    [catch {
	clock scan 2147483648 -format %Ej
    } result] $result $errorCode \
    [catch {
	clock scan 2147483648.5 -format %Ej
    } result] $result $errorCode
} [lrepeat 4 1 {requested date too large to represent} {CLOCK dateTooLarge}]

test clock-7.18 {Astronomical JDN/JD, same precedence as seconds (last wins} {
    list [clock scan {2440588 86400} -format {%Ej %s} -gmt true] \
	[clock scan {2440589 0} -format {%Ej %s} -gmt true] \
	[clock scan {86400 2440588} -format {%s %Ej} -gmt true] \
	[clock scan {0 2440589} -format {%s %Ej} -gmt true]
} {86400 0 43200 129600}

test clock-7.19 {Astronomical JDN/JD, two values} {
    clock scan {2440588 2440589} -format {%Ej %Ej} -gmt true
} 129600

test clock-7.20 {all JDN/JD are signed (and extended accept floats)} {
    set res {}
    foreach i {%J %EJ %Ej} {
	lappend res [clock scan "-1" -format $i -gmt 1]
    }
    foreach i {%EJ %Ej} {
	lappend res [clock scan "-1.5" -format $i -gmt 1]
    }
    set res
} {-210866889600 -210866889600 -210866846400 -210866846400 -210866803200}

# BEGIN testcases8

# Test parsing of ccyymmdd

test clock-8.1 {parse ccyymmdd} {
    clock scan {1970 Jan 02} -format {%C%y %b %d} -locale en_US_roman -gmt 1
................................................................................
} 1009756800
# END testcases8

test clock-9.1 {seconds take precedence over ccyymmdd} {
    clock scan {0 20000101} -format {%s %Y%m%d} -gmt true
} 0

test clock-9.2 {Calendar julian day takes precedence over ccyymmdd} {
    list \
	[clock scan {2440588 20000101} -format {%J %Y%m%d} -gmt true] \
	[clock scan {2440588 20000101} -format {%EJ %Y%m%d} -gmt true]
} {0 0}
test clock-9.2.1 {Calendar julian day (with time fraction) takes precedence over date-time} {
    list \
	[clock scan {2440588.0 20000101 010203} -format {%EJ %Y%m%d %H%M%S} -gmt true] \
	[clock scan {2440588.5 20000101 010203} -format {%EJ %Y%m%d %H%M%S} -gmt true]
    
} {0 43200}
test clock-9.3 {Astro julian day takes always precedence over date-time} {
    list \
	[clock scan {2440587.5 20000101 010203} -format {%Ej %Y%m%d %H%M%S} -gmt true] \
	[clock scan {2440588 20000101 010203} -format {%Ej %Y%m%d %H%M%S} -gmt true]
} {0 43200}

# Test parsing of ccyyddd

test clock-10.1 {parse ccyyddd} {
    clock scan {1970 001} -format {%Y %j} -locale en_US_roman -gmt 1
} 0
test clock-10.2 {parse ccyyddd} {