summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/tclClock.c85
-rw-r--r--generic/tclClockFmt.c9
-rw-r--r--generic/tclDate.c4
-rw-r--r--generic/tclDate.h20
-rw-r--r--generic/tclGetDate.y4
5 files changed, 78 insertions, 44 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c
index 1c91578..107d4e5 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -1350,20 +1350,20 @@ ClockSetupTimeZone(
Tcl_Obj *
ClockFormatNumericTimeZone(int z) {
- char sign = '+';
- int h, m;
+ char buf[12+1], *p;
+
if ( z < 0 ) {
z = -z;
- sign = '-';
+ *buf = '-';
+ } else {
+ *buf = '+';
}
- h = z / 3600;
- z %= 3600;
- m = z / 60;
- z %= 60;
+ TclItoAw(buf+1, z / 3600, '0', 2); z %= 3600;
+ p = TclItoAw(buf+3, z / 60, '0', 2); z %= 60;
if (z != 0) {
- return Tcl_ObjPrintf("%c%02d%02d%02d", sign, h, m, z);
+ p = TclItoAw(buf+5, z, '0', 2);
}
- return Tcl_ObjPrintf("%c%02d%02d", sign, h, m);
+ return Tcl_NewStringObj(buf, p - buf);
}
/*
@@ -2219,6 +2219,9 @@ ConvertUTCToLocal(
return TCL_ERROR;
}
+ /* signal we need to revalidate TZ epoch next time fields gets used. */
+ fields->flags |= CLF_CTZ;
+
/* we cannot cache (ranges unknown yet) */
} else {
Tcl_WideInt rangesVal[2];
@@ -2228,6 +2231,9 @@ ConvertUTCToLocal(
return TCL_ERROR;
}
+ /* converted using table (TZ isn't :localtime) */
+ fields->flags &= ~CLF_CTZ;
+
/* Cache the last conversion */
if (ltzoc != NULL) { /* slot was found above */
/* timezoneObj and changeover are the same */
@@ -2330,7 +2336,7 @@ ConvertUTCToLocalUsingC(
time_t tock;
struct tm *timeVal; /* Time after conversion */
int diff; /* Time zone diff local-Greenwich */
- char buffer[16]; /* Buffer for time zone name */
+ char buffer[16], *p; /* Buffer for time zone name */
/*
* Use 'localtime' to determine local year, month, day, time of day.
@@ -2383,14 +2389,12 @@ ConvertUTCToLocalUsingC(
} else {
*buffer = '+';
}
- snprintf(buffer+1, sizeof(buffer) - 1, "%02d", diff / 3600);
- diff %= 3600;
- snprintf(buffer+3, sizeof(buffer) - 3, "%02d", diff / 60);
- diff %= 60;
- if (diff > 0) {
- snprintf(buffer+5, sizeof(buffer) - 5, "%02d", diff);
+ TclItoAw(buffer+1, diff / 3600, '0', 2); diff %= 3600;
+ p = TclItoAw(buffer+3, diff / 60, '0', 2); diff %= 60;
+ if (diff != 0) {
+ p = TclItoAw(buffer+5, diff, '0', 2);
}
- Tcl_SetObjRef(fields->tzName, Tcl_NewStringObj(buffer, -1));
+ Tcl_SetObjRef(fields->tzName, Tcl_NewStringObj(buffer, p - buffer));
return TCL_OK;
}
@@ -3462,7 +3466,10 @@ baseNow:
/* check base fields already cached (by TZ, last-second cache) */
if ( dataPtr->lastBase.timezoneObj == opts->timezoneObj
- && dataPtr->lastBase.date.seconds == baseVal) {
+ && dataPtr->lastBase.date.seconds == baseVal
+ && (!(dataPtr->lastBase.date.flags & CLF_CTZ)
+ || dataPtr->lastTZEpoch == TzsetIfNecessary())
+ ) {
memcpy(date, &dataPtr->lastBase.date, ClockCacheableDateFieldsSize);
} else {
/* extact fields from base */
@@ -3986,16 +3993,23 @@ ClockFreeScan(
*/
if (info->flags & CLF_ZONE) {
- Tcl_Obj *tzObjStor = NULL;
- int minEast = -yyTimezone;
- int dstFlag = 1 - yyDSTmode;
- tzObjStor = ClockFormatNumericTimeZone(
- 60 * minEast + 3600 * dstFlag);
- Tcl_IncrRefCount(tzObjStor);
-
- opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp, tzObjStor);
-
- Tcl_DecrRefCount(tzObjStor);
+ if (yyTimezone || !yyDSTmode) {
+ /* Real time zone from numeric zone */
+ Tcl_Obj *tzObjStor = NULL;
+ int minEast = -yyTimezone;
+ int dstFlag = 1 - yyDSTmode;
+ tzObjStor = ClockFormatNumericTimeZone(
+ 60 * minEast + 3600 * dstFlag);
+ Tcl_IncrRefCount(tzObjStor);
+
+ opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp, tzObjStor);
+
+ Tcl_DecrRefCount(tzObjStor);
+ } else {
+ /* simplest case - GMT / UTC */
+ opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp,
+ dataPtr->literals[LIT_GMT]);
+ }
if (opts->timezoneObj == NULL) {
goto done;
}
@@ -4147,7 +4161,7 @@ repeat_rel:
/* relative time (seconds), if exceeds current date, do the day conversion and
* leave rest of the increment in yyRelSeconds to add it hereafter in UTC seconds */
if (yyRelSeconds) {
- int newSecs = yySecondOfDay + yyRelSeconds;
+ Tcl_WideInt newSecs = yySecondOfDay + yyRelSeconds;
/* if seconds increment outside of current date, increment day */
if (newSecs / SECONDS_PER_DAY != yySecondOfDay / SECONDS_PER_DAY) {
@@ -4392,19 +4406,22 @@ ClockAddObjCmd(
*/
for (i = 2; i < objc; i+=2) {
- /* bypass not integers (options, allready processed above) */
+ /* bypass not integers (options, allready processed above in ClockParseFmtScnArgs) */
if (TclGetWideIntFromObj(NULL, objv[i], &offs) != TCL_OK) {
continue;
}
- if (objv[i]->typePtr == &tclBignumType) {
- Tcl_SetObjResult(interp, dataPtr->literals[LIT_INTEGER_VALUE_TOO_LARGE]);
- goto done;
- }
/* get unit */
if (Tcl_GetIndexFromObj(interp, objv[i+1], units, "unit", 0,
&unitIndex) != TCL_OK) {
goto done;
}
+ if (objv[i]->typePtr == &tclBignumType
+ || offs > (unitIndex < CLC_ADD_HOURS ? 0x7fffffff : TCL_MAX_SECONDS)
+ || offs < (unitIndex < CLC_ADD_HOURS ? -0x7fffffff : TCL_MIN_SECONDS)
+ ) {
+ Tcl_SetObjResult(interp, dataPtr->literals[LIT_INTEGER_VALUE_TOO_LARGE]);
+ goto done;
+ }
/* nothing to do if zero quantity */
if (!offs) {
diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c
index f79a863..edb74ae 100644
--- a/generic/tclClockFmt.c
+++ b/generic/tclClockFmt.c
@@ -197,6 +197,15 @@ _itoaw(
return buf + width;
}
+char *
+TclItoAw(
+ char *buf,
+ int val,
+ char padchar,
+ unsigned short int width)
+{
+ return _itoaw(buf, val, padchar, width);
+}
static inline char *
_witoaw(
diff --git a/generic/tclDate.c b/generic/tclDate.c
index f4be5b6..1614bb0 100644
--- a/generic/tclDate.c
+++ b/generic/tclDate.c
@@ -139,7 +139,7 @@
typedef struct _TABLE {
const char *name;
int type;
- long value;
+ Tcl_WideInt value;
} TABLE;
/*
@@ -221,7 +221,7 @@ extern int TclDatedebug;
union YYSTYPE
{
- long Number;
+ Tcl_WideInt Number;
enum _MERIDIAN Meridian;
diff --git a/generic/tclDate.h b/generic/tclDate.h
index 5033018..3544dee 100644
--- a/generic/tclDate.h
+++ b/generic/tclDate.h
@@ -148,6 +148,8 @@ typedef enum ClockMsgCtLiteral {
* Structure containing the fields used in [clock format] and [clock scan]
*/
+#define CLF_CTZ (1 << 4)
+
typedef struct TclDateFields {
/* Cacheable fields: */
@@ -170,8 +172,10 @@ typedef struct TclDateFields {
int dayOfWeek; /* Day of the week */
int hour; /* Hours of day (in-between time only calculation) */
int minutes; /* Minutes of hour (in-between time only calculation) */
- int secondOfMin; /* Seconds of minute (in-between time only calculation) */
- int secondOfDay; /* Seconds of day (in-between time only calculation) */
+ Tcl_WideInt secondOfMin; /* Seconds of minute (in-between time only calculation) */
+ Tcl_WideInt secondOfDay; /* Seconds of day (in-between time only calculation) */
+
+ int flags; /* 0 or CLF_CTZ */
/* Non cacheable fields: */
@@ -209,16 +213,16 @@ typedef struct DateInfo {
int dateTimezone;
int dateDSTmode;
- int dateRelMonth;
- int dateRelDay;
- int dateRelSeconds;
+ Tcl_WideInt dateRelMonth;
+ Tcl_WideInt dateRelDay;
+ Tcl_WideInt dateRelSeconds;
int dateMonthOrdinalIncr;
int dateMonthOrdinal;
int dateDayOrdinal;
- int *dateRelPointer;
+ Tcl_WideInt *dateRelPointer;
int dateSpaceCount;
int dateDigitCount;
@@ -538,6 +542,10 @@ MODULE_SCOPE int ClockMCSetIdx(ClockFmtScnCmdArgs *opts, int mcKey,
/* tclClockFmt.c module declarations */
+
+MODULE_SCOPE char *
+ TclItoAw(char *buf, int val, char padchar, unsigned short int width);
+
MODULE_SCOPE Tcl_Obj*
ClockFrmObjGetLocFmtKey(Tcl_Interp *interp,
Tcl_Obj *objPtr);
diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y
index 270a3a8..0bf16e8 100644
--- a/generic/tclGetDate.y
+++ b/generic/tclGetDate.y
@@ -89,7 +89,7 @@
typedef struct _TABLE {
const char *name;
int type;
- long value;
+ Tcl_WideInt value;
} TABLE;
/*
@@ -103,7 +103,7 @@ typedef enum _DSTMODE {
%}
%union {
- long Number;
+ Tcl_WideInt Number;
enum _MERIDIAN Meridian;
}