summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-01-10 22:01:13 (GMT)
committersebres <sebres@users.sourceforge.net>2017-01-10 22:01:13 (GMT)
commit980f0e3d6b56fbddec0b97988c695f912caa5082 (patch)
tree8052cb6af5c5416aaa0fcd000063db369c21cb53
parent0e260c3cee3072b0b318b96c63a6242dec096972 (diff)
downloadtcl-980f0e3d6b56fbddec0b97988c695f912caa5082.zip
tcl-980f0e3d6b56fbddec0b97988c695f912caa5082.tar.gz
tcl-980f0e3d6b56fbddec0b97988c695f912caa5082.tar.bz2
[temp-commit]: ClockFreeScan seems to be ready, test case should be checked
-rw-r--r--generic/tclClock.c171
-rw-r--r--tests-perf/clock.perf.tcl21
2 files changed, 124 insertions, 68 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c
index 6d619e0..5710d6d 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -2560,12 +2560,13 @@ ClockFreeScan(
Tcl_Obj *timezoneObj, /* Default time zone in which the time will be expressed */
Tcl_Obj *locale) /* (Unused) Name of the locale where the time will be scanned. */
{
+ enum Flags {CL_INVALIDATE = (signed int)0x80000000};
+
ClockClientData *dataPtr = clientData;
Tcl_Obj **literals = dataPtr->literals;
DateInfo yy; /* parse structure of TclClockFreeScan */
TclDateFields date; /* date fields used for converting from seconds */
- TclDateFields date2; /* date fields used for in-between calculation */
Tcl_Obj *tzdata;
int secondOfDay; /* Seconds of day (time only calculation) */
Tcl_WideInt seconds;
@@ -2573,7 +2574,6 @@ ClockFreeScan(
// Tcl_Obj *cleanUpList = Tcl_NewObj();
date.tzName = NULL;
- date2.tzName = NULL;
/* If time zone not specified use system time zone */
if (timezoneObj == NULL ||
@@ -2670,11 +2670,14 @@ ClockFreeScan(
}
}
- SetDateFieldsTimeZone(&date, timezoneObj);
+ /* on demand (lazy) assemble julianDay using new year, month, etc. */
+ date.julianDay = CL_INVALIDATE;
- /* Assemble date, time, zone into seconds-from-epoch */
+ /*
+ * Assemble date, time, zone into seconds-from-epoch
+ */
- GetJulianDayFromEraYearMonthDay(&date, GREGORIAN_CHANGE_DATE);
+ SetDateFieldsTimeZone(&date, timezoneObj);
if (yy.dateHaveTime == -1) {
secondOfDay = 0;
@@ -2694,80 +2697,79 @@ ClockFreeScan(
secondOfDay = 0;
}
- date.localSeconds =
- -210866803200L
- + ( 86400 * (Tcl_WideInt)date.julianDay )
- + secondOfDay;
-
- SetDateFieldsTimeZone(&date, timezoneObj);
- if (ConvertLocalToUTC(interp, &date, tzdata, GREGORIAN_CHANGE_DATE)
- != TCL_OK) {
- goto done;
- }
-
- seconds = date.seconds;
-
/*
* Do relative times
*/
+repeat_rel:
+
if (yy.dateHaveRel) {
- /*
- seconds = [add $seconds \
- yy.dateRelMonth months yy.dateRelDay days yy.dateRelMonthSecond seconds \
- -timezone $timezone -locale $locale]
- */
- }
+ /* add months (or years in months) */
- /*
- * Do relative weekday
- */
+ if (yy.dateRelMonth != 0) {
+ int m, h;
- if (yy.dateHaveDay && !yy.dateHaveDate) {
+ /* if needed extract year, month, etc. again */
+ if (date.month == CL_INVALIDATE) {
+ GetGregorianEraYearDay(&date, GREGORIAN_CHANGE_DATE);
+ GetMonthDay(&date);
+ GetYearWeekDay(&date, GREGORIAN_CHANGE_DATE);
+ }
- memcpy(&date2, &date, sizeof(date));
- if (date2.tzName != NULL) {
- Tcl_IncrRefCount(date2.tzName);
- }
- /*
- SetDateFieldsTimeZone(&date2, timezoneObj);
+ /* add the requisite number of months */
+ date.month += yy.dateRelMonth - 1;
+ date.year += date.month / 12;
+ m = date.month % 12;
+ date.month = m + 1;
- date2.seconds = date.seconds;
- if (ClockGetDateFields(interp, &date2, tzdata, GREGORIAN_CHANGE_DATE)
- != TCL_OK) {
- goto done;
- }
- */
+ /* if the day doesn't exist in the current month, repair it */
+ h = hath[IsGregorianLeapYear(&date)][m];
+ if (date.dayOfMonth > h) {
+ date.dayOfMonth = h;
+ }
- date2.era = CE;
- date2.julianDay = WeekdayOnOrBefore(yy.dateDayNumber, date2.julianDay + 6)
- + 7 * yy.dateDayOrdinal;
- if (yy.dateDayOrdinal > 0) {
- date2.julianDay -= 7;
+ /* on demand (lazy) assemble julianDay using new year, month, etc. */
+ date.julianDay = CL_INVALIDATE;
+
+ yy.dateRelMonth = 0;
}
- secondOfDay = date2.localSeconds % 86400;
- date2.localSeconds =
- -210866803200
- + ( 86400 * (Tcl_WideInt)date2.julianDay )
- + secondOfDay;
-
- // check set time zone again may be really necessary here:
- // SetDateFieldsTimeZone(&date2, timezoneObj);
- if (ConvertLocalToUTC(interp, &date2, tzdata, GREGORIAN_CHANGE_DATE)
- != TCL_OK) {
- goto done;
+
+ /* add days (or other parts aligned to days) */
+ if (yy.dateRelDay) {
+
+ /* assemble julianDay using new year, month, etc. */
+ if (date.julianDay == CL_INVALIDATE) {
+ GetJulianDayFromEraYearMonthDay(&date, GREGORIAN_CHANGE_DATE);
+ }
+ date.julianDay += yy.dateRelDay;
+
+ /* julianDay was changed, on demand (lazy) extract year, month, etc. again */
+ date.month = CL_INVALIDATE;
+
+ yy.dateRelDay = 0;
}
- seconds = date2.seconds;
+ /* relative time (seconds) */
+ secondOfDay += yy.dateRelSeconds;
+ yy.dateRelSeconds = 0;
+
}
/*
- * Do relative month
+ * Do relative (ordinal) month
*/
if (yy.dateHaveOrdinalMonth) {
int monthDiff;
+
+ /* if needed extract year, month, etc. again */
+ if (date.month == CL_INVALIDATE) {
+ GetGregorianEraYearDay(&date, GREGORIAN_CHANGE_DATE);
+ GetMonthDay(&date);
+ GetYearWeekDay(&date, GREGORIAN_CHANGE_DATE);
+ }
+
if (yy.dateMonthOrdinal > 0) {
monthDiff = yy.dateMonth - date.month;
if (monthDiff <= 0) {
@@ -2781,12 +2783,54 @@ ClockFreeScan(
}
yy.dateMonthOrdinal++;
}
- /* [SB] TODO: rewrite it in C: * /
- seconds = [add $seconds $yy.dateMonthOrdinal years $monthDiff months \
- -timezone $timezone -locale $locale]
- */
+
+ /* process it further via relative times */
+ yy.dateHaveRel++;
+ date.year += yy.dateMonthOrdinal;
+ yy.dateRelMonth += monthDiff;
+ yy.dateHaveOrdinalMonth = 0;
+
+ goto repeat_rel;
+ }
+
+ /*
+ * Do relative weekday
+ */
+
+ if (yy.dateHaveDay && !yy.dateHaveDate) {
+
+ /* if needed assemble julianDay now */
+ if (date.julianDay == CL_INVALIDATE) {
+ GetJulianDayFromEraYearMonthDay(&date, GREGORIAN_CHANGE_DATE);
+ }
+
+ date.era = CE;
+ date.julianDay = WeekdayOnOrBefore(yy.dateDayNumber, date.julianDay + 6)
+ + 7 * yy.dateDayOrdinal;
+ if (yy.dateDayOrdinal > 0) {
+ date.julianDay -= 7;
+ }
+ }
+
+ /* If needed assemble julianDay using new year, month, etc. */
+ if (date.julianDay == CL_INVALIDATE) {
+ GetJulianDayFromEraYearMonthDay(&date, GREGORIAN_CHANGE_DATE);
+ }
+
+ /* Local seconds to UTC */
+
+ date.localSeconds =
+ -210866803200L
+ + ( 86400 * (Tcl_WideInt)date.julianDay )
+ + ( secondOfDay % 86400 );
+
+ if (ConvertLocalToUTC(interp, &date, tzdata, GREGORIAN_CHANGE_DATE)
+ != TCL_OK) {
+ goto done;
}
+ seconds = date.seconds;
+
ret = TCL_OK;
done:
@@ -2794,9 +2838,6 @@ done:
if (date.tzName != NULL) {
Tcl_DecrRefCount(date.tzName);
}
- if (date2.tzName != NULL) {
- Tcl_DecrRefCount(date2.tzName);
- }
// Tcl_DecrRefCount(cleanUpList);
if (ret != TCL_OK) {
diff --git a/tests-perf/clock.perf.tcl b/tests-perf/clock.perf.tcl
index 2e77a26..52bc91f 100644
--- a/tests-perf/clock.perf.tcl
+++ b/tests-perf/clock.perf.tcl
@@ -19,6 +19,18 @@ proc test-scan {{rep 100000}} {
foreach {comment c} {
"# FreeScan : relative date"
{clock scan "5 years 18 months 385 days" -base 0 -gmt 1}
+ "# FreeScan : relative date with relative weekday"
+ {clock scan "5 years 18 months 385 days Fri" -base 0 -gmt 1}
+ "# FreeScan : relative date with ordinal month"
+ {clock scan "5 years 18 months 385 days next 1 January" -base 0 -gmt 1}
+ "# FreeScan : relative date with ordinal month and relative weekday"
+ {clock scan "5 years 18 months 385 days next January Fri" -base 0 -gmt 1}
+ "# FreeScan : ordinal month"
+ {clock scan "next January" -base 0 -gmt 1}
+ "# FreeScan : relative week"
+ {clock scan "next Fri" -base 0 -gmt 1}
+ "# FreeScan : relative weekday and week offset "
+ {clock scan "next January + 2 week" -base 0 -gmt 1}
"# FreeScan : time only with base"
{clock scan "19:18:30" -base 148863600 -gmt 1}
"# FreeScan : time only without base"
@@ -34,8 +46,9 @@ proc test-scan {{rep 100000}} {
"# FreeScan : time only, zone in string (exchange zones between system / gmt)"
{clock scan "19:18:30 GMT" -base 148863600}
} {
+ if {[string first "**STOP**" $comment] != -1} { return -code error "**STOP**" }
puts "\n% $comment\n% $c"
- puts [clock format [{*}$c]]
+ puts [clock format [{*}$c] -locale en]
puts [time $c $rep]
}
}
@@ -45,15 +58,17 @@ proc test-other {{rep 100000}} {
"# Bad zone"
{catch {clock scan "1 day" -timezone BAD_ZONE}}
} {
+ if {[string first "**STOP**" $comment] != -1} { return -code error "**STOP**" }
puts "\n% $comment\n% $c"
puts [if 1 $c]
puts [time $c $rep]
}
}
+set factor 10; # 50
if 1 {;#
- test-scan 100000
- test-other 50000
+ test-scan [expr 10000 * $factor]
+ test-other [expr 5000 * $factor]
puts \n**OK**
};# \ No newline at end of file