diff options
| -rw-r--r-- | generic/tclClock.c | 55 | ||||
| -rw-r--r-- | generic/tclClockFmt.c | 33 | ||||
| -rw-r--r-- | generic/tclDate.h | 4 | ||||
| -rw-r--r-- | tests/clock.test | 14 |
4 files changed, 69 insertions, 37 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c index c648156..dba98fd 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3686,7 +3686,7 @@ ClockScanCommit( { /* If needed assemble julianDay using year, month, etc. */ if (info->flags & CLF_ASSEMBLE_JULIANDAY) { - if ((info->flags & CLF_ISO8601)) { + if ((info->flags & CLF_ISO8601WEAK)) { GetJulianDayFromEraYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE); } else @@ -3761,13 +3761,38 @@ ClockValidDate( TclDateFields temp; int tempCpyFlg = 0; - //printf("yyMonth %d, yyDay %d, yyHour %d, yyMinutes %d, yySeconds %d\n", yyMonth, yyDay, yyHour, yyMinutes, yySeconds); + // printf("yyMonth %d, yyDay %d, yyDayOfYear %d, yyHour %d, yyMinutes %d, yySeconds %d\n", yyMonth, yyDay, yydate.dayOfYear, yyHour, yyMinutes, yySeconds); if (!(stage & 1)) { goto stage_2; } - /* first month (used later in hath) */ + /* first year (used later in hath / daysInPriorMonths) */ + if ((info->flags & (CLF_YEAR|CLF_ISO8601YEAR)) || yyHaveDate) { + ClockClientData *dataPtr = opts->clientData; + + if ((info->flags & CLF_ISO8601YEAR)) { + if ( yydate.iso8601Year < dataPtr->validMinYear + || yydate.iso8601Year > dataPtr->validMaxYear ) { + errMsg = "invalid iso year"; errCode = "iso year"; goto error; + } + } + if ((info->flags & CLF_YEAR) || yyHaveDate) { + if ( yyYear < dataPtr->validMinYear + || yyYear > dataPtr->validMaxYear ) { + errMsg = "invalid year"; errCode = "year"; goto error; + } + } else if ((info->flags & CLF_ISO8601YEAR)) { + yyYear = yydate.iso8601Year; /* used to recognize leap */ + } + if ((info->flags & (CLF_ISO8601YEAR|CLF_YEAR)) + == (CLF_ISO8601YEAR|CLF_YEAR)) { + if (yyYear != yydate.iso8601Year) { + errMsg = "ambiguous year"; errCode = "year"; goto error; + } + } + } + /* and month (used later in hath) */ if ((info->flags & CLF_MONTH) || yyHaveDate) { info->flags |= CLF_MONTH; if ( yyMonth < 1 || yyMonth > 12 ) { @@ -3788,26 +3813,10 @@ ClockValidDate( } } } - if ((info->flags & (CLF_YEAR|CLF_ISO8601YEAR)) || yyHaveDate) { - ClockClientData *dataPtr = opts->clientData; - - if ((info->flags & CLF_ISO8601YEAR)) { - if ( yydate.iso8601Year < dataPtr->validMinYear - || yydate.iso8601Year > dataPtr->validMaxYear ) { - errMsg = "invalid iso year"; errCode = "iso year"; goto error; - } - } - if ((info->flags & CLF_YEAR) || yyHaveDate) { - if ( yyYear < dataPtr->validMinYear - || yyYear > dataPtr->validMaxYear ) { - errMsg = "invalid year"; errCode = "year"; goto error; - } - } - if ((info->flags & (CLF_ISO8601YEAR|CLF_YEAR)) - == (CLF_ISO8601YEAR|CLF_YEAR)) { - if (yyYear != yydate.iso8601Year) { - errMsg = "ambiguous year"; errCode = "year"; goto error; - } + if ((info->flags & CLF_DAYOFYEAR)) { + if ( yydate.dayOfYear < 1 + || yydate.dayOfYear > daysInPriorMonths[IsGregorianLeapYear(&yydate)][12] ) { + errMsg = "invalid day of year"; errCode = "day of year"; goto error; } } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index ad257d8..76a78f1 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -1781,16 +1781,16 @@ static ClockScanTokenMap ScnSTokenMap[] = { {CTOKT_INT, CLF_CENTURY|CLF_ISO8601CENTURY, 0, 1, 2, TclOffset(DateInfo, dateCentury), NULL}, /* %g */ - {CTOKT_INT, CLF_ISO8601YEAR | CLF_ISO8601, 0, 2, 2, TclOffset(DateInfo, date.iso8601Year), + {CTOKT_INT, CLF_ISO8601YEAR, 0, 2, 2, TclOffset(DateInfo, date.iso8601Year), NULL}, /* %G */ - {CTOKT_INT, CLF_ISO8601YEAR | CLF_ISO8601 | CLF_ISO8601CENTURY, 0, 4, 4, TclOffset(DateInfo, date.iso8601Year), + {CTOKT_INT, CLF_ISO8601YEAR | CLF_ISO8601CENTURY, 0, 4, 4, TclOffset(DateInfo, date.iso8601Year), NULL}, /* %V */ - {CTOKT_INT, CLF_ISO8601, 0, 1, 2, TclOffset(DateInfo, date.iso8601Week), + {CTOKT_INT, CLF_ISO8601WEAK, 0, 1, 2, TclOffset(DateInfo, date.iso8601Week), NULL}, /* %a %A %u %w */ - {CTOKT_PARSER, CLF_DAYOFWEEK | CLF_ISO8601, 0, 0, 0xffff, 0, + {CTOKT_PARSER, CLF_DAYOFWEEK | CLF_ISO8601WEAK, 0, 0, 0xffff, 0, ClockScnToken_DayOfWeek_Proc, NULL}, /* %z %Z */ {CTOKT_PARSER, CLF_OPTIONAL, 0, 0, 0xffff, 0, @@ -1854,7 +1854,7 @@ static ClockScanTokenMap ScnOTokenMap[] = { {CTOKT_PARSER, CLF_TIME, 0, 0, 0xffff, TclOffset(DateInfo, date.secondOfMin), ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS}, /* %Ou Ow */ - {CTOKT_PARSER, CLF_DAYOFWEEK | CLF_ISO8601, 0, 0, 0xffff, 0, + {CTOKT_PARSER, CLF_DAYOFWEEK | CLF_ISO8601WEAK, 0, 0, 0xffff, 0, ClockScnToken_DayOfWeek_Proc, (void *)MCLIT_LOCALE_NUMERALS}, }; static const char *ScnOTokenMapAliasIndex[2] = { @@ -2324,7 +2324,7 @@ ClockScan( case (CLF_DAYOFYEAR): /* ddd over naked weekday */ if (!(flags & CLF_ISO8601YEAR)) { - flags &= ~CLF_ISO8601; + flags &= ~CLF_ISO8601WEAK; } break; case (CLF_MONTH|CLF_DAYOFYEAR|CLF_DAYOFMONTH): @@ -2333,13 +2333,13 @@ ClockScan( case (CLF_DAYOFMONTH): /* mmdd / dd over naked weekday */ if (!(flags & CLF_ISO8601YEAR)) { - flags &= ~CLF_ISO8601; + flags &= ~CLF_ISO8601WEAK; } break; } /* YearWeekDay below YearMonthDay */ - if ( (flags & CLF_ISO8601) + if ( (flags & CLF_ISO8601WEAK) && ( (flags & (CLF_YEAR|CLF_DAYOFYEAR)) == (CLF_YEAR|CLF_DAYOFYEAR) || (flags & (CLF_YEAR|CLF_DAYOFMONTH|CLF_MONTH)) == (CLF_YEAR|CLF_DAYOFMONTH|CLF_MONTH) ) @@ -2347,16 +2347,16 @@ ClockScan( /* yy precedence below yyyy */ if (!(flags & CLF_ISO8601CENTURY) && (flags & CLF_CENTURY)) { /* normally precedence of ISO is higher, but no century - so put it down */ - flags &= ~CLF_ISO8601; + flags &= ~CLF_ISO8601WEAK; } else /* yymmdd or yyddd over naked weekday */ if (!(flags & CLF_ISO8601YEAR)) { - flags &= ~CLF_ISO8601; + flags &= ~CLF_ISO8601WEAK; } } - if ( (flags & CLF_YEAR) || !(flags & CLF_ISO8601) ) { + if ( (flags & CLF_YEAR) ) { if (yyYear < 100) { if (!(flags & CLF_CENTURY)) { if (yyYear >= dataPtr->yearOfCenturySwitch) { @@ -2368,7 +2368,12 @@ ClockScan( } } } - if ( (flags & CLF_ISO8601) ) { + if ( (flags & (CLF_ISO8601WEAK|CLF_ISO8601YEAR)) ) { + if ((flags & (CLF_ISO8601YEAR|CLF_YEAR)) == CLF_YEAR) { + /* for calculations expected iso year */ + info->date.iso8601Year = yyYear; + } + else if (info->date.iso8601Year < 100) { if (!(flags & CLF_ISO8601CENTURY)) { if (info->date.iso8601Year >= dataPtr->yearOfCenturySwitch) { @@ -2379,6 +2384,10 @@ ClockScan( info->date.iso8601Year += info->dateCentury * 100; } } + if ((flags & (CLF_ISO8601YEAR|CLF_YEAR)) == CLF_ISO8601YEAR) { + /* for calculations expected year (e. g. CLF_ISO8601WEAK not set) */ + yyYear = info->date.iso8601Year; + } } } } diff --git a/generic/tclDate.h b/generic/tclDate.h index fd85611..9ce5dc8 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -44,7 +44,7 @@ #define CLF_YEAR (1 << 10) #define CLF_DAYOFWEEK (1 << 11) #define CLF_ISO8601YEAR (1 << 12) -#define CLF_ISO8601 (1 << 13) +#define CLF_ISO8601WEAK (1 << 13) #define CLF_ISO8601CENTURY (1 << 14) #define CLF_SIGNED (1 << 15) /* On demand (lazy) assemble flags */ @@ -53,7 +53,7 @@ #define CLF_ASSEMBLE_SECONDS (1 << 30) /* assemble localSeconds (and seconds at end) */ #define CLF_DATE (CLF_JULIANDAY | CLF_DAYOFMONTH | CLF_DAYOFYEAR | \ - CLF_MONTH | CLF_YEAR | CLF_ISO8601YEAR | CLF_ISO8601) + CLF_MONTH | CLF_YEAR | CLF_ISO8601YEAR | CLF_ISO8601WEAK) /* * Enumeration of the string literals used in [clock] diff --git a/tests/clock.test b/tests/clock.test index aab2c5e..7c16990 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36645,6 +36645,20 @@ test clock-46.28.vm$valid_mode {scan: validation rules: invalid day of week} \ -body { list [catch {clock scan "Sat Jan 01 00:00:00 1970" -format "%a %b %d %H:%M:%S %Y" -valid 1 -gmt 1} msg] $msg } -result {1 {unable to convert input string: invalid day of week}} +test clock-46.29-1.vm$valid_mode {scan: validation rules: invalid day of year} \ + -body { + list [catch {clock scan "000-2017" -format "%j-%Y" -valid 1 -gmt 1} msg] $msg \ + [catch {clock scan "366-2017" -format "%j-%Y" -valid 1 -gmt 1} msg] $msg \ + [catch {clock scan "000-2017" -format "%j-%G" -valid 1 -gmt 1} msg] $msg \ + [catch {clock scan "366-2017" -format "%j-%G" -valid 1 -gmt 1} msg] $msg + } -result [lrepeat 4 1 {unable to convert input string: invalid day of year}] +test clock-46.29-2.vm$valid_mode {scan: validation rules: valid day of leap/not leap year} \ + -body { + list [clock format [clock scan "366-2016" -format "%j-%Y" -valid 1 -gmt 1] -format "%d-%m-%Y"] \ + [clock format [clock scan "365-2017" -format "%j-%Y" -valid 1 -gmt 1] -format "%d-%m-%Y"] \ + [clock format [clock scan "366-2016" -format "%j-%G" -valid 1 -gmt 1] -format "%d-%m-%Y"] \ + [clock format [clock scan "365-2017" -format "%j-%G" -valid 1 -gmt 1] -format "%d-%m-%Y"] + } -result {31-12-2016 31-12-2017 31-12-2016 31-12-2017} test clock-46.30.vm$valid_mode {scan: validation rules: invalid year} -setup { set orgcfg [list -min-year [clock configure -min-year] -max-year [clock configure -max-year] \ -year-century [clock configure -year-century] -century-switch [clock configure -century-switch]] |
