Tcl Source Code

Check-in [9095503f61]
Login

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

Overview
Comment:scan: extended with token `%EJ` to scan calendar julian day with time fraction (in opposite to astronomical JD `%Ej` it starts at midnight like `%J` token).
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | clock-astronomical-jdn
Files: files | file ages | folders
SHA3-256: 9095503f61bb82e86c0e521a86ae01280fc93c969f5a675d9a8ee0f716697e58
User & Date: sebres 2019-03-13 00:23:57.875
Context
2019-03-13
00:24
format: add support of new JDN-tokens (calendar JD `%EJ`, astronomical JD `%Ej`) with time fraction.... check-in: 2194d065f7 user: sebres tags: clock-astronomical-jdn
00:23
scan: extended with token `%EJ` to scan calendar julian day with time fraction (in opposite to astro... check-in: 9095503f61 user: sebres tags: clock-astronomical-jdn
00:21
implemented scan of astronomical julian day (JDN/ID) with token `%Ej`, corresponds julian date of sq... check-in: b9804722b9 user: sebres tags: clock-astronomical-jdn
Changes
Unified Diff Ignore Whitespace Patch
Changes to doc/clock.n.
394
395
396
397
398
399
400
401

402
403
404
405
406
407
408
409
410
411
412
.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.
Note, that in case of \fB%Ej\fR format group, representing
the astronomical Julian Date (with time fraction), this group is 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.







|
>
|
|
|
|







394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
.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.
562
563
564
565
566
567
568











569
570
571
572
573
574
575
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%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







>
>
>
>
>
>
>
>
>
>
>







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
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
Changes to generic/tclClockFmt.c.
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
	*(int *)(((char *)info) + tok->map->offs) = --val;
    }

    return TCL_OK;
}

static int
ClockScnToken_AstroJDN_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++; };
    s = p;
    while (p < end && isdigit(UCHAR(*p))) {
	p++;
    }
    if ( _str2wideInt(&intJD, s, p, 1) != TCL_OK) {
	return TCL_RETURN;
    };
    yyInput = p;
    if (p >= end || *p++ != '.') { /* allow pure integer astronomical JDN */


	goto done;




    }
    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 = (SECONDS_PER_DAY/2)
	+ (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 );



    return TCL_OK;
}

static int
ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts,
    DateInfo *info, ClockScanToken *tok)







|




















|
>
>
|
>
>
>
>

















|




|







>
>







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
	*(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++; };
    s = p;
    while (p < end && isdigit(UCHAR(*p))) {
	p++;
    }
    if ( _str2wideInt(&intJD, s, p, 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 | CLF_SIGNED;

    return TCL_OK;
}

static int
ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts,
    DateInfo *info, ClockScanToken *tok)
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880



1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
};
static const char *ScnSTokenMapAliasIndex[2] = {
    "eNBhkIlPAuwZW",
    "dmbbHHHpaaazU"
};

static const char *ScnETokenMapIndex =
    "Ejys";
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_POSIXSEC | CLF_SIGNED, 0, 1, 0xffff, 0,
	ClockScnToken_AstroJDN_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},
};







|




>
>
>

|
|







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
};
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, 0, 1, 0xffff, 0, /* calendar JDN starts at midnight */
	ClockScnToken_JDN_Proc, NULL},
    /* %Ej */
    {CTOKT_PARSER, CLF_JULIANDAY, 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},
};
2381
2382
2383
2384
2385
2386
2387

2388
2389
2390
2391
2392
2393
2394
	}
	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;







>







2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
	}
	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;
Changes to tests/clock.test.
18895
18896
18897
18898
18899
18900
18901








18902
18903
18904
18905
18906
18907
18908
	[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.11 {Astronomical JDN/JD} {
    clock scan 0 -format %Ej -gmt true
} -210866760000

test clock-7.12 {Astronomical JDN/JD} {







>
>
>
>
>
>
>
>







18895
18896
18897
18898
18899
18900
18901
18902
18903
18904
18905
18906
18907
18908
18909
18910
18911
18912
18913
18914
18915
18916
	[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} {
21372
21373
21374
21375
21376
21377
21378
21379

21380

21381






21382

21383

21384
21385
21386
21387
21388
21389
21390
21391
} 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 clock-9.2.1 {Astro julian day takes precedence over date-time} {

    clock scan {2440587.5 20000101 010203} -format {%Ej %Y%m%d %H%M%S} -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} {







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







21380
21381
21382
21383
21384
21385
21386
21387
21388
21389
21390
21391
21392
21393
21394
21395
21396
21397
21398
21399
21400
21401
21402
21403
21404
21405
21406
21407
21408
21409
} 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} {