summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2018-05-29 17:25:48 (GMT)
committersebres <sebres@users.sourceforge.net>2018-05-29 17:25:48 (GMT)
commit3cf665c0f5505d9c3eec3b6d0c8e5bd0a12f777b (patch)
tree19bc988c13c5a258ee59876a87fd73ae389d9647
parentef90044383d683cd7f71f7235932efec03fa7b93 (diff)
downloadtcl-3cf665c0f5505d9c3eec3b6d0c8e5bd0a12f777b.zip
tcl-3cf665c0f5505d9c3eec3b6d0c8e5bd0a12f777b.tar.gz
tcl-3cf665c0f5505d9c3eec3b6d0c8e5bd0a12f777b.tar.bz2
validation rules: extended for day of year (and test covered now)
-rw-r--r--generic/tclClock.c55
-rw-r--r--generic/tclClockFmt.c33
-rw-r--r--generic/tclDate.h4
-rw-r--r--tests/clock.test14
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]]