summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-01-10 22:32:46 (GMT)
committersebres <sebres@users.sourceforge.net>2017-01-10 22:32:46 (GMT)
commit6795fcaa4965863daab7cdaa16fff4b551044586 (patch)
tree9a9aa264652ce9b5d39a10b6ef22f98c9730e64b
parent8fb97e54a5d09f6cb6faab31efe48b7dd0670467 (diff)
downloadtcl-6795fcaa4965863daab7cdaa16fff4b551044586.zip
tcl-6795fcaa4965863daab7cdaa16fff4b551044586.tar.gz
tcl-6795fcaa4965863daab7cdaa16fff4b551044586.tar.bz2
scan format: several tokens implemented, bug fixing and code review;
precedence yyyymmdd over yyyyddd was changed (and re-covered in test-cases also), see http://core.tcl.tk/tcl/tktview/e7a722cd3573fedda5d1e528f95902776f996e06
-rw-r--r--generic/tclClock.c25
-rw-r--r--generic/tclClockFmt.c384
-rw-r--r--generic/tclDate.h21
-rwxr-xr-xlibrary/clock.tcl37
-rw-r--r--library/msgcat/msgcat.tcl5
-rw-r--r--tests/clock.test66
6 files changed, 436 insertions, 102 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c
index ef0e46b..1a5141b 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -473,13 +473,12 @@ ClockMCDict(ClockFmtScnCmdArgs *opts)
}
if (opts->mcDictObj == NULL) {
- Tcl_Obj *callargs[3];
- /* get msgcat dictionary - ::msgcat::mcget ::tcl::clock locale */
+ Tcl_Obj *callargs[2];
+ /* get msgcat dictionary - ::tcl::clock::mcget locale */
callargs[0] = dataPtr->literals[LIT_MCGET];
- callargs[1] = dataPtr->literals[LIT_TCL_CLOCK];
- callargs[2] = opts->localeObj;
+ callargs[1] = opts->localeObj;
- if (Tcl_EvalObjv(opts->interp, 3, callargs, 0) != TCL_OK) {
+ if (Tcl_EvalObjv(opts->interp, 2, callargs, 0) != TCL_OK) {
return NULL;
}
@@ -823,7 +822,7 @@ ClockGetSystemTimeZone(
/*
*----------------------------------------------------------------------
*/
-static Tcl_Obj *
+MODULE_SCOPE Tcl_Obj *
ClockSetupTimeZone(
ClientData clientData, /* Opaque pointer to literal pool, etc. */
Tcl_Interp *interp, /* Tcl interpreter */
@@ -2948,7 +2947,11 @@ ClockScanObjCmd(
/* If needed assemble julianDay using year, month, etc. */
if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
- if ((info->flags & CLF_DAYOFMONTH) || !(info->flags & CLF_DAYOFYEAR)) {
+ if ((info->flags & CLF_ISO8601)) {
+ GetJulianDayFromEraYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
+ }
+ else
+ if (!(info->flags & CLF_DAYOFYEAR)) {
GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
} else {
GetJulianDayFromEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
@@ -3065,11 +3068,11 @@ ClockFreeScan(
int dstFlag = 1 - yyDSTmode;
tzObjStor = ClockFormatNumericTimeZone(
60 * minEast + 3600 * dstFlag);
-
+ Tcl_IncrRefCount(tzObjStor);
+
opts->timezoneObj = ClockSetupTimeZone(clientData, interp, tzObjStor);
- if (tzObjStor != opts->timezoneObj) {
- Tcl_DecrRefCount(tzObjStor);
- }
+
+ Tcl_DecrRefCount(tzObjStor);
if (opts->timezoneObj == NULL) {
goto done;
}
diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c
index 2c1dfc1..f965a17 100644
--- a/generic/tclClockFmt.c
+++ b/generic/tclClockFmt.c
@@ -508,27 +508,14 @@ void DetermineGreedySearchLen(ClockFmtScnCmdArgs *opts,
}
}
-static int
-LocaleListSearch(ClockFmtScnCmdArgs *opts,
- DateInfo *info, int mcKey, int *val,
+inline int
+ObjListSearch(ClockFmtScnCmdArgs *opts,
+ DateInfo *info, int *val,
+ Tcl_Obj **lstv, int lstc,
int minLen, int maxLen)
{
- Tcl_Obj **lstv;
- int lstc, i, l, lf = -1;
+ int i, l, lf = -1;
const char *s;
- Tcl_Obj *valObj;
-
- /* get msgcat value */
- valObj = ClockMCGet(opts, mcKey);
- if (valObj == NULL) {
- return TCL_ERROR;
- }
-
- /* is a list */
- if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
- return TCL_ERROR;
- }
-
/* search in list */
for (i = 0; i < lstc; i++) {
s = TclGetString(lstv[i]);
@@ -561,6 +548,31 @@ LocaleListSearch(ClockFmtScnCmdArgs *opts,
}
static int
+LocaleListSearch(ClockFmtScnCmdArgs *opts,
+ DateInfo *info, int mcKey, int *val,
+ int minLen, int maxLen)
+{
+ Tcl_Obj **lstv;
+ int lstc;
+ Tcl_Obj *valObj;
+
+ /* get msgcat value */
+ valObj = ClockMCGet(opts, mcKey);
+ if (valObj == NULL) {
+ return TCL_ERROR;
+ }
+
+ /* is a list */
+ if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /* search in list */
+ return ObjListSearch(opts, info, val, lstv, lstc,
+ minLen, maxLen);
+}
+
+static int
StaticListSearch(ClockFmtScnCmdArgs *opts,
DateInfo *info, const char **lst, int *val)
{
@@ -631,8 +643,7 @@ ClockScnToken_Month_Proc(ClockFmtScnCmdArgs *opts,
*/
int ret, val;
- int minLen;
- int maxLen;
+ int minLen, maxLen;
DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
@@ -653,15 +664,115 @@ ClockScnToken_Month_Proc(ClockFmtScnCmdArgs *opts,
return TCL_OK;
}
+
+static int
+ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts,
+ DateInfo *info, ClockScanToken *tok)
+{
+ int ret, val;
+ int minLen, maxLen;
+ char curTok = *tok->tokWord.start;
+
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
+
+ /* %u %w %Ou %Ow */
+ if ( curTok != 'a' && curTok != 'A'
+ && ((minLen <= 1 && maxLen >= 1) || (int)tok->map->data)
+ ) {
+
+ val = -1;
+
+ if (!(int)tok->map->data) {
+ if (*yyInput >= '0' && *yyInput <= '9') {
+ val = *yyInput - '0';
+ }
+ } else {
+ int ret = LocaleListSearch(opts, info, (int)tok->map->data, &val,
+ minLen, maxLen);
+ if (ret == TCL_ERROR) {
+ return ret;
+ }
+ }
+
+ if (val != -1) {
+ if (val == 0) {
+ val = 7;
+ }
+ if (val > 7 && curTok != 'a' && curTok != 'A') {
+ Tcl_SetResult(opts->interp, "day of week is greater than 7",
+ TCL_STATIC);
+ Tcl_SetErrorCode(opts->interp, "CLOCK", "badDayOfWeek", NULL);
+ return TCL_ERROR;
+ }
+ info->date.dayOfWeek = val;
+ yyInput++;
+ return TCL_OK;
+ }
+
+
+ return TCL_RETURN;
+ }
+
+ /* %a %A */
+ ret = LocaleListSearch(opts, info, MCLIT_DAYS_OF_WEEK_FULL, &val,
+ minLen, maxLen);
+ if (ret != TCL_OK) {
+ /* if not found */
+ if (ret == TCL_RETURN) {
+ ret = LocaleListSearch(opts, info, MCLIT_DAYS_OF_WEEK_ABBREV, &val,
+ minLen, maxLen);
+ }
+ if (ret != TCL_OK) {
+ return ret;
+ }
+ }
+
+ if (val == 0) {
+ val = 7;
+ }
+ info->date.dayOfWeek = val;
+ return TCL_OK;
+
+}
+
+static int
+ClockScnToken_amPmInd_Proc(ClockFmtScnCmdArgs *opts,
+ DateInfo *info, ClockScanToken *tok)
+{
+ int ret, val;
+ int minLen, maxLen;
+ Tcl_Obj *amPmObj[2];
+
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
+
+ amPmObj[0] = ClockMCGet(opts, MCLIT_AM);
+ amPmObj[1] = ClockMCGet(opts, MCLIT_PM);
+
+ if (amPmObj[0] == NULL || amPmObj == NULL) {
+ return TCL_ERROR;
+ }
+
+ ret = ObjListSearch(opts, info, &val, amPmObj, 2,
+ minLen, maxLen);
+ if (ret != TCL_OK) {
+ return ret;
+ }
+
+ if (val == 0) {
+ yyMeridian = MERam;
+ } else {
+ yyMeridian = MERpm;
+ }
+ return TCL_OK;
+}
static int
ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts,
DateInfo *info, ClockScanToken *tok)
{
int ret, val;
- int minLen;
- int maxLen;
+ int minLen, maxLen;
DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
@@ -675,27 +786,106 @@ ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts,
return TCL_OK;
}
+
+static int
+ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts,
+ DateInfo *info, ClockScanToken *tok)
+{
+ int minLen, maxLen;
+ int len = 0;
+ register const char *p = yyInput;
+ Tcl_Obj *tzObjStor = NULL;
+
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
+
+ /* numeric timezone */
+ if (*p == '+' || *p == '-') {
+ /* max chars in numeric zone = "+00:00:00" */
+ #define MAX_ZONE_LEN 9
+ char buf[MAX_ZONE_LEN + 1];
+ char *bp = buf;
+ *bp++ = *p++; len++;
+ if (maxLen > MAX_ZONE_LEN)
+ maxLen = MAX_ZONE_LEN;
+ /* cumulate zone into buf without ':' */
+ while (len + 1 < maxLen) {
+ if (!isdigit(UCHAR(*p))) break;
+ *bp++ = *p++; len++;
+ if (!isdigit(UCHAR(*p))) break;
+ *bp++ = *p++; len++;
+ if (len + 2 < maxLen) {
+ if (*p == ':') {
+ *p++; len++;
+ }
+ }
+ }
+ *bp = '\0';
+
+ if (len < minLen) {
+ return TCL_RETURN;
+ }
+ #undef MAX_ZONE_LEN
+
+ /* timezone */
+ tzObjStor = Tcl_NewStringObj(buf, bp-buf);
+ } else {
+ /* legacy (alnum) timezone like CEST, etc. */
+ if (maxLen > 4)
+ maxLen = 4;
+ while (len < maxLen) {
+ if ( (*p & 0x80)
+ || (!isalpha(UCHAR(*p)) && !isdigit(UCHAR(*p)))
+ ) { /* INTL: ISO only. */
+ break;
+ }
+ p++; len++;
+ }
+ if (len < minLen) {
+ return TCL_RETURN;
+ }
+
+ /* timezone */
+ tzObjStor = Tcl_NewStringObj(yyInput, p-yyInput);
+
+ /* convert using dict */
+ }
+
+ /* try to apply new time zone */
+ Tcl_IncrRefCount(tzObjStor);
+
+ opts->timezoneObj = ClockSetupTimeZone(opts->clientData, opts->interp,
+ tzObjStor);
+
+ Tcl_DecrRefCount(tzObjStor);
+ if (opts->timezoneObj == NULL) {
+ return TCL_ERROR;
+ }
+
+ yyInput += len;
+ return TCL_OK;
+}
+
static const char *ScnSTokenMapIndex =
- "dmbyYHMSJjCs";
+ "dmbyYHMSpJjCgGVazs";
static ClockScanTokenMap ScnSTokenMap[] = {
/* %d %e */
- {CTOKT_DIGIT, CLF_DATE | CLF_DAYOFMONTH, CLF_DAYOFYEAR, 1, 2, TclOffset(DateInfo, date.dayOfMonth),
+ {CTOKT_DIGIT, CLF_DAYOFMONTH, 0, 1, 2, TclOffset(DateInfo, date.dayOfMonth),
NULL},
/* %m */
- {CTOKT_DIGIT, CLF_DATE, CLF_DAYOFYEAR, 1, 2, TclOffset(DateInfo, date.month),
+ {CTOKT_DIGIT, CLF_MONTH, 0, 1, 2, TclOffset(DateInfo, date.month),
NULL},
/* %b %B %h */
- {CTOKT_PARSER, CLF_DATE, CLF_DAYOFYEAR, 0, 0, 0,
+ {CTOKT_PARSER, CLF_MONTH, 0, 0, 0, 0,
ClockScnToken_Month_Proc},
/* %y */
- {CTOKT_DIGIT, CLF_DATE, 0, 1, 2, TclOffset(DateInfo, date.year),
+ {CTOKT_DIGIT, CLF_YEAR, 0, 1, 2, TclOffset(DateInfo, date.year),
NULL},
/* %Y */
- {CTOKT_DIGIT, CLF_DATE | CLF_CENTURY, 0, 1, 4, TclOffset(DateInfo, date.year),
+ {CTOKT_DIGIT, CLF_YEAR | CLF_CENTURY, 0, 1, 4, TclOffset(DateInfo, date.year),
NULL},
- /* %H */
+ /* %H %k %I %l */
{CTOKT_DIGIT, CLF_TIME, 0, 1, 2, TclOffset(DateInfo, date.hour),
NULL},
/* %M */
@@ -704,22 +894,40 @@ static ClockScanTokenMap ScnSTokenMap[] = {
/* %S */
{CTOKT_DIGIT, CLF_TIME, 0, 1, 2, TclOffset(DateInfo, date.secondOfDay),
NULL},
+ /* %p %P */
+ {CTOKT_PARSER, CLF_ISO8601, 0, 0, 0, 0,
+ ClockScnToken_amPmInd_Proc, NULL},
/* %J */
- {CTOKT_DIGIT, CLF_DATE | CLF_JULIANDAY, 0, 1, 0xffff, TclOffset(DateInfo, date.julianDay),
+ {CTOKT_DIGIT, CLF_JULIANDAY, 0, 1, 0xffff, TclOffset(DateInfo, date.julianDay),
NULL},
/* %j */
- {CTOKT_DIGIT, CLF_DATE | CLF_DAYOFYEAR, CLF_DAYOFMONTH, 1, 3, TclOffset(DateInfo, date.dayOfYear),
+ {CTOKT_DIGIT, CLF_DAYOFYEAR, 0, 1, 3, TclOffset(DateInfo, date.dayOfYear),
NULL},
/* %C */
- {CTOKT_DIGIT, CLF_DATE | CLF_CENTURY, 0, 1, 2, TclOffset(DateInfo, dateCentury),
+ {CTOKT_DIGIT, CLF_CENTURY|CLF_ISO8601CENTURY, 0, 1, 2, TclOffset(DateInfo, dateCentury),
+ NULL},
+ /* %g */
+ {CTOKT_DIGIT, CLF_ISO8601YEAR | CLF_ISO8601, 0, 2, 2, TclOffset(DateInfo, date.iso8601Year),
+ NULL},
+ /* %G */
+ {CTOKT_DIGIT, CLF_ISO8601YEAR | CLF_ISO8601 | CLF_ISO8601CENTURY, 0, 1, 4, TclOffset(DateInfo, date.iso8601Year),
NULL},
+ /* %V */
+ {CTOKT_DIGIT, CLF_ISO8601, 0, 1, 2, TclOffset(DateInfo, date.iso8601Week),
+ NULL},
+ /* %a %A %u %w */
+ {CTOKT_PARSER, CLF_ISO8601, 0, 0, 0, 0,
+ ClockScnToken_DayOfWeek_Proc, NULL},
+ /* %z %Z */
+ {CTOKT_PARSER, 0, 0, 0, 0, 0,
+ ClockScnToken_TimeZone_Proc, NULL},
/* %s */
{CTOKT_DIGIT, CLF_LOCALSEC | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.localSeconds),
NULL},
};
static const char *ScnSTokenWrapMapIndex[2] = {
- "eNBh",
- "dmbb"
+ "eNBhkIlPAuwZ",
+ "dmbbHHHpaaaz"
};
static const char *ScnETokenMapIndex =
@@ -733,18 +941,33 @@ static const char *ScnETokenWrapMapIndex[2] = {
};
static const char *ScnOTokenMapIndex =
- "dm";
+ "dmyHMSu";
static ClockScanTokenMap ScnOTokenMap[] = {
/* %Od %Oe */
- {CTOKT_PARSER, CLF_DATE | CLF_DAYOFMONTH, CLF_DAYOFYEAR, 0, 0, TclOffset(DateInfo, date.dayOfMonth),
+ {CTOKT_PARSER, CLF_DAYOFMONTH, 0, 0, 0, TclOffset(DateInfo, date.dayOfMonth),
ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
/* %Om */
- {CTOKT_PARSER, CLF_DATE, CLF_DAYOFYEAR, 0, 0, TclOffset(DateInfo, date.month),
+ {CTOKT_PARSER, CLF_MONTH, 0, 0, 0, TclOffset(DateInfo, date.month),
+ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
+ /* %Oy */
+ {CTOKT_PARSER, CLF_YEAR, 0, 0, 0, TclOffset(DateInfo, date.year),
+ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
+ /* %OH %Ok %OI %Ol */
+ {CTOKT_PARSER, CLF_TIME, 0, 0, 0, TclOffset(DateInfo, date.hour),
+ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
+ /* %OM */
+ {CTOKT_PARSER, CLF_TIME, 0, 0, 0, TclOffset(DateInfo, date.minutes),
ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
+ /* %OS */
+ {CTOKT_PARSER, CLF_TIME, 0, 0, 0, TclOffset(DateInfo, date.secondOfDay),
+ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
+ /* %Ou Ow */
+ {CTOKT_PARSER, CLF_ISO8601, 0, 0, 0, 0,
+ ClockScnToken_DayOfWeek_Proc, (void *)MCLIT_LOCALE_NUMERALS},
};
static const char *ScnOTokenWrapMapIndex[2] = {
- "e",
- "d"
+ "ekIlw",
+ "dHHHu"
};
static const char *ScnSpecTokenMapIndex =
@@ -1153,7 +1376,6 @@ ClockScan(
/*
* Invalidate result
*/
- info->flags |= flags;
/* seconds token (%s) take precedence over all other tokens */
if ((opts->flags & CLF_EXTENDED) || !(flags & CLF_LOCALSEC)) {
@@ -1162,23 +1384,78 @@ ClockScan(
if (!(flags & CLF_JULIANDAY)) {
info->flags |= CLF_ASSEMBLE_SECONDS|CLF_ASSEMBLE_JULIANDAY;
- if (yyYear < 100) {
- if (!(flags & CLF_CENTURY)) {
- if (yyYear >= dataPtr->yearOfCenturySwitch) {
- yyYear -= 100;
+ /* dd precedence below ddd */
+ switch (flags & (CLF_MONTH|CLF_DAYOFYEAR|CLF_DAYOFMONTH)) {
+ case (CLF_DAYOFYEAR|CLF_DAYOFMONTH):
+ /* miss month: ddd over dd (without month) */
+ flags &= ~CLF_DAYOFMONTH;
+ case (CLF_DAYOFYEAR):
+ /* ddd over naked weekday */
+ if (!(flags & CLF_ISO8601YEAR)) {
+ flags &= ~CLF_ISO8601;
+ }
+ break;
+ case (CLF_MONTH|CLF_DAYOFYEAR|CLF_DAYOFMONTH):
+ /* both available: mmdd over ddd */
+ flags &= ~CLF_DAYOFYEAR;
+ case (CLF_MONTH|CLF_DAYOFMONTH):
+ case (CLF_DAYOFMONTH):
+ /* mmdd / dd over naked weekday */
+ if (!(flags & CLF_ISO8601YEAR)) {
+ flags &= ~CLF_ISO8601;
+ }
+ break;
+ }
+
+ /* YearWeekDay below YearMonthDay */
+ if ( (flags & CLF_ISO8601)
+ && ( (flags & (CLF_YEAR|CLF_DAYOFYEAR)) == (CLF_YEAR|CLF_DAYOFYEAR)
+ || (flags & (CLF_YEAR|CLF_DAYOFMONTH|CLF_MONTH)) == (CLF_YEAR|CLF_DAYOFMONTH|CLF_MONTH)
+ )
+ ) {
+ /* 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;
+ }
+ else
+ /* yymmdd or yyddd over naked weekday */
+ if (!(flags & CLF_ISO8601YEAR)) {
+ flags &= ~CLF_ISO8601;
+ }
+ }
+
+ if (!(flags & CLF_ISO8601)) {
+ if (yyYear < 100) {
+ if (!(flags & CLF_CENTURY)) {
+ if (yyYear >= dataPtr->yearOfCenturySwitch) {
+ yyYear -= 100;
+ }
+ yyYear += dataPtr->currentYearCentury;
+ } else {
+ yyYear += info->dateCentury * 100;
+ }
+ }
+ } else {
+ if (info->date.iso8601Year < 100) {
+ if (!(flags & CLF_ISO8601CENTURY)) {
+ if (info->date.iso8601Year >= dataPtr->yearOfCenturySwitch) {
+ info->date.iso8601Year -= 100;
+ }
+ info->date.iso8601Year += dataPtr->currentYearCentury;
+ } else {
+ info->date.iso8601Year += info->dateCentury * 100;
}
- yyYear += dataPtr->currentYearCentury;
- } else {
- yyYear += info->dateCentury * 100;
}
}
yydate.era = CE;
}
- /* if date but no time - reset time */
- if (!(flags & (CLF_TIME|CLF_LOCALSEC))) {
- info->flags |= CLF_ASSEMBLE_SECONDS;
- yydate.localSeconds = 0;
- }
+ }
+
+ /* if no time - reset time */
+ if (!(flags & (CLF_TIME|CLF_LOCALSEC))) {
+ info->flags |= CLF_ASSEMBLE_SECONDS;
+ yydate.localSeconds = 0;
}
if (flags & CLF_TIME) {
@@ -1192,6 +1469,9 @@ ClockScan(
}
}
+ /* tell caller which flags were set */
+ info->flags |= flags;
+
ret = TCL_OK;
goto done;
diff --git a/generic/tclDate.h b/generic/tclDate.h
index 23fe5b3..fc922cb 100644
--- a/generic/tclDate.h
+++ b/generic/tclDate.h
@@ -30,19 +30,26 @@
#define ONE_YEAR 365 /* days */
-#define CLF_DATE (1 << 2)
#define CLF_JULIANDAY (1 << 3)
#define CLF_TIME (1 << 4)
#define CLF_LOCALSEC (1 << 5)
#define CLF_CENTURY (1 << 6)
#define CLF_DAYOFMONTH (1 << 7)
#define CLF_DAYOFYEAR (1 << 8)
+#define CLF_MONTH (1 << 9)
+#define CLF_YEAR (1 << 10)
+#define CLF_ISO8601YEAR (1 << 12)
+#define CLF_ISO8601 (1 << 13)
+#define CLF_ISO8601CENTURY (1 << 14)
#define CLF_SIGNED (1 << 15)
/* On demand (lazy) assemble flags */
#define CLF_ASSEMBLE_DATE (1 << 28) /* assemble year, month, etc. using julianDay */
#define CLF_ASSEMBLE_JULIANDAY (1 << 29) /* assemble julianDay using year, month, etc. */
#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)
+
/*
* Enumeration of the string literals used in [clock]
@@ -87,7 +94,7 @@ typedef enum ClockLiteral {
"::tcl::clock::TZData", \
"::tcl::clock::GetSystemTimeZone", \
"::tcl::clock::SetupTimeZone", \
- "::msgcat::mcget", "::tcl::clock", \
+ "::tcl::clock::mcget", "::tcl::clock", \
"::tcl::clock::LocalizeFormat" \
}
@@ -96,13 +103,19 @@ typedef enum ClockLiteral {
*/
typedef enum ClockMsgCtLiteral {
+ MCLIT__NIL, /* placeholder */
MCLIT_MONTHS_FULL, MCLIT_MONTHS_ABBREV,
+ MCLIT_DAYS_OF_WEEK_FULL, MCLIT_DAYS_OF_WEEK_ABBREV,
+ MCLIT_AM, MCLIT_PM,
MCLIT_LOCALE_NUMERALS,
MCLIT__END
} ClockMsgCtLiteral;
#define CLOCK_LOCALE_LITERAL_ARRAY(litarr, pref) static const char *const litarr[] = { \
+ pref "", \
pref "MONTHS_FULL", pref "MONTHS_ABBREV", \
+ pref "DAYS_OF_WEEK_FULL", pref "DAYS_OF_WEEK_ABBREV", \
+ pref "AM", pref "PM", \
pref "LOCALE_NUMERALS", \
}
@@ -406,6 +419,10 @@ MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info);
/* tclClock.c module declarations */
MODULE_SCOPE Tcl_Obj *
+ ClockSetupTimeZone(ClientData clientData,
+ Tcl_Interp *interp, Tcl_Obj *timezoneObj);
+
+MODULE_SCOPE Tcl_Obj *
ClockMCDict(ClockFmtScnCmdArgs *opts);
MODULE_SCOPE Tcl_Obj *
ClockMCGet(ClockFmtScnCmdArgs *opts, int mcKey);
diff --git a/library/clock.tcl b/library/clock.tcl
index a532c0d..d4e29d5 100755
--- a/library/clock.tcl
+++ b/library/clock.tcl
@@ -629,15 +629,17 @@ proc ::tcl::clock::Initialize {} {
# Caches
- variable LocaleFormats {}; # Dictionary with localized formats
+ variable LocaleFormats \
+ [dict create]; # Dictionary with localized formats
- variable LocaleNumeralCache {}; # Dictionary whose keys are locale
+ variable LocaleNumeralCache \
+ [dict create]; # Dictionary whose keys are locale
# names and whose values are pairs
# comprising regexes matching numerals
# in the given locales and dictionaries
# mapping the numerals to their numeric
# values.
- variable TimeZoneBad {}; # Dictionary whose keys are time zone
+ variable TimeZoneBad [dict create]; # Dictionary whose keys are time zone
# names and whose values are 1 if
# the time zone is unknown and 0
# if it is known.
@@ -653,6 +655,17 @@ proc ::tcl::clock::Initialize {} {
::tcl::clock::Initialize
#----------------------------------------------------------------------
+
+proc mcget {locale args} {
+ switch -- $locale system {
+ set locale [GetSystemLocale]
+ } current {
+ set locale [mclocale]
+ }
+ msgcat::mcget ::tcl::clock $locale {*}$args
+}
+
+#----------------------------------------------------------------------
#
# clock format --
#
@@ -2938,7 +2951,7 @@ proc ::tcl::clock::ConvertLegacyTimeZone { tzname } {
#
#----------------------------------------------------------------------
-proc ::tcl::clock::SetupTimeZone { timezone } {
+proc ::tcl::clock::SetupTimeZone { timezone {alias {}} } {
variable TZData
if {! [info exists TZData($timezone)] } {
@@ -3005,6 +3018,19 @@ proc ::tcl::clock::SetupTimeZone { timezone } {
}
} else {
+
+ variable LegacyTimeZone
+
+ # Check may be a legacy zone:
+ if { $alias eq {} && ![catch {
+ set tzname [dict get $LegacyTimeZone [string tolower $timezone]]
+ }] } {
+ set tzname [::tcl::clock::SetupTimeZone $tzname $timezone]
+ set TZData($timezone) $TZData($tzname)
+ # tell backend - timezone is initialized and return shared timezone object:
+ return [configure -setup-tz $timezone]
+ }
+
# We couldn't parse this as a POSIX time zone. Try again with a
# time zone file - this time without a colon
@@ -4472,6 +4498,9 @@ proc ::tcl::clock::ClearCaches {} {
# tell backend - should invalidate:
configure -clear
+ # clear msgcat cache:
+ msgcat::ClearCaches ::tcl::clock
+
foreach p [info procs [namespace current]::scanproc'*] {
rename $p {}
}
diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl
index a25f6c8..e6452d2 100644
--- a/library/msgcat/msgcat.tcl
+++ b/library/msgcat/msgcat.tcl
@@ -951,6 +951,11 @@ proc msgcat::Merge {ns locales} {
return [dict smartref $mrgcat]
}
+proc msgcat::ClearCaches {ns} {
+ variable Merged
+ dict unset Merged $ns
+}
+
# msgcat::Invoke --
#
# Invoke a set of registered callbacks.
diff --git a/tests/clock.test b/tests/clock.test
index 22b5bc1..e96dec6 100644
--- a/tests/clock.test
+++ b/tests/clock.test
@@ -21070,78 +21070,78 @@ test clock-10.10 {julian day takes precedence over ccyyddd} {
# BEGIN testcases11
-# Test precedence among yyyymmdd and yyyyddd
+# Test precedence yyyymmdd over yyyyddd
-test clock-11.1 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.1 {precedence of ccyymmdd over ccyyddd} {
clock scan 19700101002 -format %Y%m%d%j -gmt 1
-} 86400
-test clock-11.2 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.2 {precedence of ccyymmdd over ccyyddd} {
clock scan 01197001002 -format %m%Y%d%j -gmt 1
-} 86400
-test clock-11.3 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.3 {precedence of ccyymmdd over ccyyddd} {
clock scan 01197001002 -format %d%Y%m%j -gmt 1
-} 86400
-test clock-11.4 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.4 {precedence of ccyymmdd over ccyyddd} {
clock scan 00219700101 -format %j%Y%m%d -gmt 1
} 0
-test clock-11.5 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.5 {precedence of ccyymmdd over ccyyddd} {
clock scan 19700100201 -format %Y%m%j%d -gmt 1
} 0
-test clock-11.6 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.6 {precedence of ccyymmdd over ccyyddd} {
clock scan 01197000201 -format %m%Y%j%d -gmt 1
} 0
-test clock-11.7 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.7 {precedence of ccyymmdd over ccyyddd} {
clock scan 01197000201 -format %d%Y%j%m -gmt 1
} 0
-test clock-11.8 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.8 {precedence of ccyymmdd over ccyyddd} {
clock scan 00219700101 -format %j%Y%d%m -gmt 1
} 0
-test clock-11.9 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.9 {precedence of ccyymmdd over ccyyddd} {
clock scan 19700101002 -format %Y%d%m%j -gmt 1
-} 86400
-test clock-11.10 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.10 {precedence of ccyymmdd over ccyyddd} {
clock scan 01011970002 -format %m%d%Y%j -gmt 1
-} 86400
-test clock-11.11 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.11 {precedence of ccyymmdd over ccyyddd} {
clock scan 01011970002 -format %d%m%Y%j -gmt 1
-} 86400
-test clock-11.12 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.12 {precedence of ccyymmdd over ccyyddd} {
clock scan 00201197001 -format %j%m%Y%d -gmt 1
} 0
-test clock-11.13 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.13 {precedence of ccyymmdd over ccyyddd} {
clock scan 19700100201 -format %Y%d%j%m -gmt 1
} 0
-test clock-11.14 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.14 {precedence of ccyymmdd over ccyyddd} {
clock scan 01010021970 -format %m%d%j%Y -gmt 1
-} 86400
-test clock-11.15 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.15 {precedence of ccyymmdd over ccyyddd} {
clock scan 01010021970 -format %d%m%j%Y -gmt 1
-} 86400
-test clock-11.16 {precedence of ccyyddd and ccyymmdd} {
+} 0
+test clock-11.16 {precedence of ccyymmdd over ccyyddd} {
clock scan 00201011970 -format %j%m%d%Y -gmt 1
} 0
-test clock-11.17 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.17 {precedence of ccyymmdd over ccyyddd} {
clock scan 19700020101 -format %Y%j%m%d -gmt 1
} 0
-test clock-11.18 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.18 {precedence of ccyymmdd over ccyyddd} {
clock scan 01002197001 -format %m%j%Y%d -gmt 1
} 0
-test clock-11.19 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.19 {precedence of ccyymmdd over ccyyddd} {
clock scan 01002197001 -format %d%j%Y%m -gmt 1
} 0
-test clock-11.20 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.20 {precedence of ccyymmdd over ccyyddd} {
clock scan 00201197001 -format %j%d%Y%m -gmt 1
} 0
-test clock-11.21 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.21 {precedence of ccyymmdd over ccyyddd} {
clock scan 19700020101 -format %Y%j%d%m -gmt 1
} 0
-test clock-11.22 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.22 {precedence of ccyymmdd over ccyyddd} {
clock scan 01002011970 -format %m%j%d%Y -gmt 1
} 0
-test clock-11.23 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.23 {precedence of ccyymmdd over ccyyddd} {
clock scan 01002011970 -format %d%j%m%Y -gmt 1
} 0
-test clock-11.24 {precedence of ccyyddd and ccyymmdd} {
+test clock-11.24 {precedence of ccyymmdd over ccyyddd} {
clock scan 00201011970 -format %j%d%m%Y -gmt 1
} 0
# END testcases11