[njs] Refactored working with Date object.
Dmitry Volyntsev
xeioex at nginx.com
Fri Nov 8 13:30:17 UTC 2019
details: https://hg.nginx.org/njs/rev/f770bdea7c85
branches:
changeset: 1226:f770bdea7c85
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Nov 08 16:29:29 2019 +0300
description:
Refactored working with Date object.
1) Replacing gmtime_r() and localtime_r() with builtin function.
2) Custom getters and setters for each field (like hours, minutes,
seconds) are replaced with generic functions.
diffstat:
auto/time | 16 +
src/njs_date.c | 1730 +++++++++------------------------------------
src/test/njs_unit_test.c | 49 +-
3 files changed, 408 insertions(+), 1387 deletions(-)
diffs (truncated from 2507 to 1000 lines):
diff -r 6df48738a043 -r f770bdea7c85 auto/time
--- a/auto/time Fri Nov 08 16:29:24 2019 +0300
+++ b/auto/time Fri Nov 08 16:29:29 2019 +0300
@@ -33,6 +33,22 @@ if [ $njs_found = no ]; then
fi
fi
+
+njs_feature="sizeof(time_t)"
+njs_feature_name=NJS_TIME_T_SIZE
+njs_feature_run=value
+njs_feature_incs=
+njs_feature_libs=
+njs_feature_test="#include <time.h>
+ #include <stdio.h>
+
+ int main(void) {
+ printf(\"%zu\", sizeof(time_t));
+ return 0;
+ }"
+. auto/feature
+
+
# Linux, FreeBSD, MacOSX.
njs_feature="struct tm.tm_gmtoff"
diff -r 6df48738a043 -r f770bdea7c85 src/njs_date.c
--- a/src/njs_date.c Fri Nov 08 16:29:24 2019 +0300
+++ b/src/njs_date.c Fri Nov 08 16:29:29 2019 +0300
@@ -8,15 +8,27 @@
#include <njs_main.h>
-/*
- * njs_timegm() is used because
- * Solaris lacks timegm(),
- * FreeBSD and MacOSX timegm() cannot handle years before 1900.
- */
-
#define NJS_DATE_TIME_LEN \
sizeof("Mon Sep 28 1970 12:00:00 GMT+0600 (XXXXX)")
+#define NJS_DATE_MAX_FIELDS 8
+#define NJS_DATE_WDAY 0
+#define NJS_DATE_YR 1
+#define NJS_DATE_MON 2
+#define NJS_DATE_DAY 3
+#define NJS_DATE_HR 4
+#define NJS_DATE_MIN 5
+#define NJS_DATE_SEC 6
+#define NJS_DATE_MSEC 7
+
+
+#define njs_date_magic(field, local) \
+ ((local << 6) + field)
+
+
+#define njs_date_magic2(since, len, local) \
+ ((local << 6) + ((len & 7) << 3) + since)
+
typedef enum {
NJS_DATE_FMT_TO_TIME_STRING,
@@ -28,23 +40,20 @@ typedef enum {
static double njs_date_string_parse(njs_value_t *date);
-static double njs_date_rfc2822_string_parse(struct tm *tm, const u_char *p,
+static double njs_date_rfc2822_string_parse(int64_t tm[], const u_char *p,
const u_char *end);
-static double njs_date_js_string_parse(struct tm *tm, const u_char *p,
+static double njs_date_js_string_parse(int64_t tm[], const u_char *p,
const u_char *end);
static const u_char *njs_date_skip_week_day(const u_char *p, const u_char *end);
static const u_char *njs_date_skip_spaces(const u_char *p, const u_char *end);
static njs_int_t njs_date_month_parse(const u_char *p, const u_char *end);
-static const u_char *njs_date_time_parse(struct tm *tm, const u_char *p,
+static const u_char *njs_date_time_parse(int64_t tm[], const u_char *p,
const u_char *end);
-static njs_int_t njs_date_gmtoff_parse(const u_char *start, const u_char *end);
-static const u_char *njs_date_number_parse(int *value, const u_char *p,
+static int64_t njs_date_gmtoff_parse(const u_char *start, const u_char *end);
+static const u_char *njs_date_number_parse(int64_t *value, const u_char *p,
const u_char *end, size_t size);
-static int64_t njs_timegm(struct tm *tm);
static njs_int_t njs_date_string(njs_vm_t *vm, njs_value_t *retval,
njs_date_fmt_t fmt, double time);
-static double njs_date_time(struct tm *tm, int64_t ms);
-static double njs_date_utc_time(struct tm *tm, double time);
static const njs_value_t njs_string_invalid_date = njs_string("Invalid Date");
@@ -95,13 +104,6 @@ njs_timeclip(double time)
njs_inline int64_t
-njs_make_time(int64_t h, int64_t min, int64_t s, int64_t milli)
-{
- return ((h * 60 + min) * 60 + s) * 1000 + milli;
-}
-
-
-njs_inline int64_t
njs_days_in_year(int64_t y)
{
return 365 + !(y % 4) - !(y % 100) + !(y % 400);
@@ -152,25 +154,151 @@ njs_tz_offset(int64_t time)
time /= 1000;
+#if (NJS_TIME_T_SIZE < 8)
+
+ /* Smart truncation. */
+
+ if ((time_t) -1 < 0) {
+ if (time < INT32_MIN) {
+ time = INT32_MIN;
+
+ } else if (time > INT32_MAX) {
+ time = INT32_MAX;
+ }
+
+ } else {
+ if (time < 0) {
+ time = 0;
+
+ } else if (time > UINT32_MAX) {
+ time = UINT32_MAX;
+ }
+ }
+
+#endif
+
ti = time;
localtime_r(&ti, &tm);
+ /*
+ * As njs_timezone(&tm) may return value which is not a multiple of 60
+ * secs (see "zdump -v /etc/localtime" for MSK zone) rounding it to
+ * minutes precision here to ensure:
+ * var date = new Date(<args>)
+ * date.valueOf() - date.getTimezoneOffset() * 60000 == Date.UTC(<args>)
+ * which is expected by test262.
+ */
+
return -njs_timezone(&tm) / 60;
}
njs_inline int64_t
-njs_make_date(int64_t days, int64_t time, njs_bool_t local)
+njs_year_from_days(int64_t *days)
{
- int64_t date;
+ int64_t y, d1, nd, d;
+
+ d = *days;
+
+ y = njs_floor_div(d * 10000, 3652425) + 1970;
+
+ for ( ;; ) {
+ d1 = d - njs_days_from_year(y);
+
+ if (d1 < 0) {
+ y--;
+ d1 += njs_days_in_year(y);
+
+ } else {
+ nd = njs_days_in_year(y);
+
+ if (d1 < nd) {
+ break;
+ }
- date = days * 86400000 + time;
+ d1 -= nd;
+ y++;
+ }
+ }
+
+ *days = d1;
+
+ return y;
+}
+
+
+njs_inline double
+njs_make_date(int64_t tm[], njs_bool_t local)
+{
+ int64_t days, time;
+
+ days = njs_make_day(tm[NJS_DATE_YR], tm[NJS_DATE_MON],
+ tm[NJS_DATE_DAY]);
+
+ time = ((tm[NJS_DATE_HR] * 60 + tm[NJS_DATE_MIN]) * 60
+ + tm[NJS_DATE_SEC]) * 1000 + tm[NJS_DATE_MSEC];
+
+ time += days * 86400000;
if (local) {
- date += njs_tz_offset(date) * 60000;
+ time += njs_tz_offset(time) * 60000;
+ }
+
+ return njs_timeclip(time);
+}
+
+
+njs_inline int64_t
+njs_destruct_date(double time, int64_t tm[], int index, njs_bool_t local)
+{
+ int64_t days, wd, y, i, md, h, m, s, ms;
+
+ static const int month_days[] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 };
+
+ if (njs_slow_path(isnan(time))) {
+ time = 0;
+
+ } else if (local) {
+ time -= njs_tz_offset(time) * 60000;
}
- return date;
+ h = njs_mod(time, 86400000);
+ days = (time - h) / 86400000;
+ ms = h % 1000;
+ h = (h - ms) / 1000;
+ s = h % 60;
+ h = (h - s) / 60;
+ m = h % 60;
+ h = (h - m) / 60;
+ wd = njs_mod(days + 4, 7);
+ y = njs_year_from_days(&days);
+
+ for (i = 0; i < 11; i++) {
+ md = month_days[i];
+
+ if (i == 1) {
+ /* Leap day. */
+ md += njs_days_in_year(y) - 365;
+ }
+
+ if (days < md) {
+ break;
+ }
+
+ days -= md;
+ }
+
+ tm[NJS_DATE_YR] = y;
+ tm[NJS_DATE_MON] = i;
+ tm[NJS_DATE_DAY] = days + 1;
+ tm[NJS_DATE_HR] = h;
+ tm[NJS_DATE_MIN] = m;
+ tm[NJS_DATE_SEC] = s;
+ tm[NJS_DATE_MSEC] = ms;
+ tm[NJS_DATE_WDAY] = wd;
+
+ return tm[index];
}
@@ -179,11 +307,10 @@ njs_date_constructor(njs_vm_t *vm, njs_v
njs_index_t unused)
{
double num, time;
- int64_t day, tm;
njs_int_t ret;
njs_uint_t i, n;
njs_date_t *date;
- int64_t values[8];
+ int64_t tm[NJS_DATE_MAX_FIELDS];
if (!vm->top_frame->ctor) {
return njs_date_string(vm, &vm->retval, NJS_DATE_FMT_TO_STRING,
@@ -210,17 +337,16 @@ njs_date_constructor(njs_vm_t *vm, njs_v
time = njs_date_string_parse(&args[1]);
} else {
- time = njs_number(&args[1]);
+ time = njs_timeclip(njs_number(&args[1]));
}
} else {
time = NAN;
- njs_memzero(values, 8 * sizeof(int64_t));
+ njs_memzero(tm, NJS_DATE_MAX_FIELDS * sizeof(int64_t));
- /* Day. */
- values[3] = 1;
+ tm[NJS_DATE_DAY] = 1;
n = njs_min(8, nargs);
@@ -238,19 +364,14 @@ njs_date_constructor(njs_vm_t *vm, njs_v
goto done;
}
- values[i] = num;
+ tm[i] = num;
}
- /* Year. */
- if (values[1] >= 0 && values[1] < 100) {
- values[1] += 1900;
+ if (tm[NJS_DATE_YR] >= 0 && tm[NJS_DATE_YR] < 100) {
+ tm[NJS_DATE_YR] += 1900;
}
- day = njs_make_day(values[1], values[2], values[3]);
-
- tm = njs_make_time(values[4], values[5], values[6], values[7]);
-
- time = njs_make_date(day, tm, 1);
+ time = njs_make_date(tm, 1);
}
done:
@@ -268,7 +389,7 @@ done:
date->object.extensible = 1;
date->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_DATE].object;
- date->time = njs_timeclip(time);
+ date->time = time;
njs_set_date(&vm->retval, date);
@@ -280,19 +401,17 @@ static njs_int_t
njs_date_utc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- int64_t day, tm;
double num, time;
njs_int_t ret;
njs_uint_t i, n;
- int64_t values[8];
+ int64_t tm[NJS_DATE_MAX_FIELDS];
time = NAN;
if (nargs > 1) {
- njs_memzero(values, 8 * sizeof(int64_t));
+ njs_memzero(tm, NJS_DATE_MAX_FIELDS * sizeof(int64_t));
- /* Day. */
- values[3] = 1;
+ tm[NJS_DATE_DAY] = 1;
n = njs_min(8, nargs);
@@ -310,18 +429,15 @@ njs_date_utc(njs_vm_t *vm, njs_value_t *
goto done;
}
- values[i] = num;
+ tm[i] = num;
}
/* Year. */
- if (values[1] >= 0 && values[1] < 100) {
- values[1] += 1900;
+ if (tm[NJS_DATE_YR] >= 0 && tm[NJS_DATE_YR] < 100) {
+ tm[NJS_DATE_YR] += 1900;
}
- day = njs_make_day(values[1], values[2], values[3]);
- tm = njs_make_time(values[4], values[5], values[6], values[7]);
-
- time = njs_timeclip(njs_make_date(day, tm, 0));
+ time = njs_make_date(tm, 0);
}
done:
@@ -332,55 +448,6 @@ done:
}
-static int64_t
-njs_timegm(struct tm *tm)
-{
- int32_t year, month, days;
-
- year = tm->tm_year + 1900;
-
- /*
- * Shift new year to March 1 and start months
- * from 1 (not 0), as required for Gauss' formula.
- */
-
- month = tm->tm_mon - 1;
-
- if (month <= 0) {
- month += 12;
- year -= 1;
- }
-
- /* Gauss' formula for Gregorian days since March 1, 1 BCE. */
-
- /* Days in years including leap years since March 1, 1 BCE. */
- days = 365 * year + year / 4 - year / 100 + year / 400;
-
- /* Days before the month. */
- days += 367 * month / 12 - 30;
-
- /* Days before the day. */
- if (year >= 0) {
- days += tm->tm_mday - 1;
-
- } else {
- /* 1 BCE was a leap year. */
- days += tm->tm_mday - 2;
- }
-
- /*
- * 719527 days were between March 1, 1 BCE and March 1, 1970,
- * 31 and 28 days were in January and February 1970.
- */
- days = days - 719527 + 31 + 28;
-
- return (int64_t) days * 86400
- + tm->tm_hour * 3600
- + tm->tm_min * 60
- + tm->tm_sec;
-}
-
-
static njs_int_t
njs_date_now(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
@@ -421,12 +488,12 @@ njs_date_parse(njs_vm_t *vm, njs_value_t
static double
njs_date_string_parse(njs_value_t *date)
{
- int ext, ms, ms_length, skipped;
- double time;
- njs_str_t string;
- struct tm tm;
- njs_bool_t sign, week, utc;
- const u_char *p, *next, *end;
+ size_t ms_length;
+ int64_t ext, skipped;
+ njs_str_t string;
+ njs_bool_t sign, week, utc;
+ const u_char *p, *next, *end;
+ int64_t tm[NJS_DATE_MAX_FIELDS];
njs_string_get(date, &string);
@@ -445,19 +512,20 @@ njs_date_string_parse(njs_value_t *date)
sign = 0;
}
- tm.tm_mon = 0;
- tm.tm_mday = 1;
- tm.tm_hour = 0;
- tm.tm_min = 0;
- tm.tm_sec = 0;
+ tm[NJS_DATE_MON] = 0;
+ tm[NJS_DATE_DAY] = 1;
+ tm[NJS_DATE_HR] = 0;
+ tm[NJS_DATE_MIN] = 0;
+ tm[NJS_DATE_SEC] = 0;
+ tm[NJS_DATE_MSEC] = 0;
- next = njs_date_number_parse(&tm.tm_year, p, end, 4);
+ next = njs_date_number_parse(&tm[NJS_DATE_YR], p, end, 4);
if (next != NULL) {
/* ISO-8601 format: "1970-09-28T06:00:00.000Z" */
if (next == end) {
- goto year;
+ goto done;
}
if (*next != '-') {
@@ -468,18 +536,19 @@ njs_date_string_parse(njs_value_t *date)
return NAN;
}
- tm.tm_year = tm.tm_year * 100 + ext;
+ tm[NJS_DATE_YR] *= 100;
+ tm[NJS_DATE_YR] += ext;
if (string.start[0] == '-') {
- if (tm.tm_year == 0) {
+ if (tm[NJS_DATE_YR] == 0) {
return NAN;
}
- tm.tm_year = -tm.tm_year;
+ tm[NJS_DATE_YR] = -tm[NJS_DATE_YR];
}
if (next == end) {
- goto year;
+ goto done;
}
if (*next != '-') {
@@ -487,14 +556,12 @@ njs_date_string_parse(njs_value_t *date)
}
}
- tm.tm_year -= 1900;
-
- p = njs_date_number_parse(&tm.tm_mon, next + 1, end, 2);
+ p = njs_date_number_parse(&tm[NJS_DATE_MON], next + 1, end, 2);
if (njs_slow_path(p == NULL)) {
return NAN;
}
- tm.tm_mon--;
+ tm[NJS_DATE_MON]--;
if (p == end) {
goto done;
@@ -504,7 +571,7 @@ njs_date_string_parse(njs_value_t *date)
return NAN;
}
- p = njs_date_number_parse(&tm.tm_mday, p + 1, end, 2);
+ p = njs_date_number_parse(&tm[NJS_DATE_DAY], p + 1, end, 2);
if (njs_slow_path(p == NULL)) {
return NAN;
}
@@ -525,7 +592,7 @@ njs_date_string_parse(njs_value_t *date)
end++;
}
- p = njs_date_time_parse(&tm, p + 1, end);
+ p = njs_date_time_parse(tm, p + 1, end);
if (njs_slow_path(p == NULL)) {
return NAN;
}
@@ -542,7 +609,7 @@ njs_date_string_parse(njs_value_t *date)
ms_length = (end - p < 3) ? end - p : 3;
- p = njs_date_number_parse(&ms, p, end, ms_length);
+ p = njs_date_number_parse(&tm[NJS_DATE_MSEC], p, end, ms_length);
if (njs_slow_path(p == NULL)) {
return NAN;
}
@@ -555,21 +622,13 @@ njs_date_string_parse(njs_value_t *date)
}
if (ms_length == 1) {
- ms *= 100;
+ tm[NJS_DATE_MSEC] *= 100;
} else if (ms_length == 2) {
- ms *= 10;
+ tm[NJS_DATE_MSEC] *= 10;
}
- if (utc) {
- time = njs_timegm(&tm);
-
- } else {
- tm.tm_isdst = -1;
- time = mktime(&tm);
- }
-
- return time * 1000 + ms;
+ return njs_make_date(tm, !utc);
}
if (sign) {
@@ -579,7 +638,7 @@ njs_date_string_parse(njs_value_t *date)
week = 1;
for ( ;; ) {
- next = njs_date_number_parse(&tm.tm_mday, p, end, 2);
+ next = njs_date_number_parse(&tm[NJS_DATE_DAY], p, end, 2);
if (next != NULL) {
/*
@@ -588,15 +647,15 @@ njs_date_string_parse(njs_value_t *date)
* "Mon, 28 Sep 1970 06:00:00 UTC",
* "Mon, 28 Sep 1970 12:00:00 +0600".
*/
- return njs_date_rfc2822_string_parse(&tm, next, end);
+ return njs_date_rfc2822_string_parse(tm, next, end);
}
- tm.tm_mon = njs_date_month_parse(p, end);
+ tm[NJS_DATE_MON] = njs_date_month_parse(p, end);
- if (tm.tm_mon >= 0) {
+ if (tm[NJS_DATE_MON] >= 0) {
/* Date.toString() format: "Mon Sep 28 1970 12:00:00 GMT+0600". */
- return njs_date_js_string_parse(&tm, p + 3, end);
+ return njs_date_js_string_parse(tm, p + 3, end);
}
if (!week) {
@@ -616,28 +675,24 @@ njs_date_string_parse(njs_value_t *date)
week = 0;
}
-year:
-
- tm.tm_year -= 1900;
-
done:
- return njs_timegm(&tm) * 1000;
+ return njs_make_date(tm, 0);
}
static double
-njs_date_rfc2822_string_parse(struct tm *tm, const u_char *p, const u_char *end)
+njs_date_rfc2822_string_parse(int64_t tm[], const u_char *p, const u_char *end)
{
- int gmtoff;
+ int64_t gmtoff;
p = njs_date_skip_spaces(p, end);
if (njs_slow_path(p == NULL)) {
return NAN;
}
- tm->tm_mon = njs_date_month_parse(p, end);
- if (njs_slow_path(tm->tm_mon < 0)) {
+ tm[NJS_DATE_MON] = njs_date_month_parse(p, end);
+ if (njs_slow_path(tm[NJS_DATE_MON] < 0)) {
return NAN;
}
@@ -646,12 +701,12 @@ njs_date_rfc2822_string_parse(struct tm
return NAN;
}
- p = njs_date_number_parse(&tm->tm_year, p, end, 4);
+ p = njs_date_number_parse(&tm[NJS_DATE_YR], p, end, 4);
if (njs_slow_path(p == NULL)) {
return NAN;
}
- tm->tm_year -= 1900;
+ gmtoff = 0;
if (p == end) {
goto done;
@@ -701,25 +756,25 @@ njs_date_rfc2822_string_parse(struct tm
}
}
- return (njs_timegm(tm) - gmtoff * 60) * 1000;
-
done:
- return njs_timegm(tm) * 1000;
+ tm[NJS_DATE_MSEC] = -gmtoff * 60000;
+
+ return njs_make_date(tm, 0);
}
static double
-njs_date_js_string_parse(struct tm *tm, const u_char *p, const u_char *end)
+njs_date_js_string_parse(int64_t tm[], const u_char *p, const u_char *end)
{
- int gmtoff;
+ int64_t gmtoff;
p = njs_date_skip_spaces(p, end);
if (njs_slow_path(p == NULL)) {
return NAN;
}
- p = njs_date_number_parse(&tm->tm_mday, p, end, 2);
+ p = njs_date_number_parse(&tm[NJS_DATE_DAY], p, end, 2);
if (njs_slow_path(p == NULL)) {
return NAN;
}
@@ -729,13 +784,11 @@ njs_date_js_string_parse(struct tm *tm,
return NAN;
}
- p = njs_date_number_parse(&tm->tm_year, p, end, 4);
+ p = njs_date_number_parse(&tm[NJS_DATE_YR], p, end, 4);
if (njs_slow_path(p == NULL)) {
return NAN;
}
- tm->tm_year -= 1900;
-
if (p == end) {
goto done;
}
@@ -768,11 +821,11 @@ njs_date_js_string_parse(struct tm *tm,
}
if (p + 2 < end && p[0] == 'G' && p[1] == 'M' && p[2] == 'T') {
-
gmtoff = njs_date_gmtoff_parse(&p[3], end);
if (njs_fast_path(gmtoff != -1)) {
- return (njs_timegm(tm) - gmtoff * 60) * 1000;
+ tm[NJS_DATE_MSEC] = -gmtoff * 60000;
+ return njs_make_date(tm, 0);
}
}
@@ -780,7 +833,7 @@ njs_date_js_string_parse(struct tm *tm,
done:
- return njs_timegm(tm) * 1000;
+ return njs_make_date(tm, 0);
}
@@ -908,9 +961,9 @@ njs_date_month_parse(const u_char *p, co
static const u_char *
-njs_date_time_parse(struct tm *tm, const u_char *p, const u_char *end)
+njs_date_time_parse(int64_t tm[], const u_char *p, const u_char *end)
{
- p = njs_date_number_parse(&tm->tm_hour, p, end, 2);
+ p = njs_date_number_parse(&tm[NJS_DATE_HR], p, end, 2);
if (njs_slow_path(p == NULL)) {
return p;
}
@@ -919,7 +972,7 @@ njs_date_time_parse(struct tm *tm, const
return NULL;
}
- p = njs_date_number_parse(&tm->tm_min, p + 1, end, 2);
+ p = njs_date_number_parse(&tm[NJS_DATE_MIN], p + 1, end, 2);
if (njs_slow_path(p == NULL)) {
return p;
}
@@ -932,14 +985,14 @@ njs_date_time_parse(struct tm *tm, const
return NULL;
}
- return njs_date_number_parse(&tm->tm_sec, p + 1, end, 2);
+ return njs_date_number_parse(&tm[NJS_DATE_SEC], p + 1, end, 2);
}
-static njs_int_t
+static int64_t
njs_date_gmtoff_parse(const u_char *start, const u_char *end)
{
- int gmtoff, hour, min;
+ int64_t gmtoff, hour, min;
const u_char *p;
if (njs_fast_path(start + 4 < end && (*start == '+' || *start == '-'))) {
@@ -968,7 +1021,7 @@ njs_date_gmtoff_parse(const u_char *star
static const u_char *
-njs_date_number_parse(int *value, const u_char *p, const u_char *end,
+njs_date_number_parse(int64_t *value, const u_char *p, const u_char *end,
size_t size)
{
u_char c;
@@ -1128,11 +1181,10 @@ static njs_int_t
njs_date_string(njs_vm_t *vm, njs_value_t *retval, njs_date_fmt_t fmt,
double time)
{
- u_char *p, sign;
- int32_t year, tz;
- time_t clock;
- u_char buf[NJS_DATE_TIME_LEN];
- struct tm tm;
+ int year, tz;
+ u_char *p, sign;
+ u_char buf[NJS_DATE_TIME_LEN];
+ int64_t tm[NJS_DATE_MAX_FIELDS];
static const char *week[] = { "Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat" };
@@ -1150,15 +1202,15 @@ njs_date_string(njs_vm_t *vm, njs_value_
switch (fmt) {
case NJS_DATE_FMT_TO_ISO_STRING:
case NJS_DATE_FMT_TO_UTC_STRING:
- clock = time / 1000;
- gmtime_r(&clock, &tm);
- year = tm.tm_year + 1900;
+ njs_destruct_date(time, tm, 0, 0);
+ year = tm[NJS_DATE_YR];
if (fmt == NJS_DATE_FMT_TO_UTC_STRING) {
p = njs_sprintf(p, buf + NJS_DATE_TIME_LEN,
- "%s, %02d %s %04d %02d:%02d:%02d GMT",
- week[tm.tm_wday], tm.tm_mday, month[tm.tm_mon],
- year, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ "%s, %02L %s %04d %02L:%02L:%02L GMT",
+ week[tm[NJS_DATE_WDAY]], tm[NJS_DATE_DAY],
+ month[tm[NJS_DATE_MON]], year, tm[NJS_DATE_HR],
+ tm[NJS_DATE_MIN], tm[NJS_DATE_SEC]);
break;
}
@@ -1175,10 +1227,9 @@ njs_date_string(njs_vm_t *vm, njs_value_
}
p = njs_sprintf(p, buf + NJS_DATE_TIME_LEN,
- "-%02d-%02dT%02d:%02d:%02d.%03dZ",
- tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
- tm.tm_min, tm.tm_sec,
- (int) ((int64_t) time % 1000));
+ "-%02L-%02LT%02L:%02L:%02L.%03LZ",
+ tm[NJS_DATE_MON] + 1, tm[NJS_DATE_DAY], tm[NJS_DATE_HR],
+ tm[NJS_DATE_MIN], tm[NJS_DATE_SEC], tm[NJS_DATE_MSEC]);
break;
@@ -1186,14 +1237,13 @@ njs_date_string(njs_vm_t *vm, njs_value_
case NJS_DATE_FMT_TO_DATE_STRING:
case NJS_DATE_FMT_TO_STRING:
default:
- clock = time / 1000;
- localtime_r(&clock, &tm);
+ njs_destruct_date(time, tm, 0, 1);
if (fmt != NJS_DATE_FMT_TO_TIME_STRING) {
p = njs_sprintf(p, buf + NJS_DATE_TIME_LEN,
- "%s %s %02d %04d",
- week[tm.tm_wday], month[tm.tm_mon], tm.tm_mday,
- tm.tm_year + 1900);
+ "%s %s %02L %04L",
+ week[tm[NJS_DATE_WDAY]], month[tm[NJS_DATE_MON]],
+ tm[NJS_DATE_DAY], tm[NJS_DATE_YR]);
}
if (fmt != NJS_DATE_FMT_TO_DATE_STRING) {
@@ -1209,8 +1259,8 @@ njs_date_string(njs_vm_t *vm, njs_value_
}
p = njs_sprintf(p, buf + NJS_DATE_TIME_LEN,
- "%02d:%02d:%02d GMT%c%02d%02d",
- tm.tm_hour, tm.tm_min, tm.tm_sec,
+ "%02L:%02L:%02L GMT%c%02d%02d",
+ tm[NJS_DATE_HR], tm[NJS_DATE_MIN], tm[NJS_DATE_SEC],
sign, tz / 60, tz % 60);
}
}
@@ -1259,193 +1309,11 @@ njs_date_to_string(njs_vm_t *vm, njs_val
static njs_int_t
-njs_date_prototype_get_full_year(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
-{
- double value;
- time_t clock;
- struct tm tm;
-
- if (njs_slow_path(!njs_is_date(&args[0]))) {
- njs_type_error(vm, "cannot convert %s to date",
- njs_type_string(args[0].type));
-
- return NJS_ERROR;
- }
-
- value = njs_date(&args[0])->time;
-
- if (njs_fast_path(!isnan(value))) {
- clock = value / 1000;
- localtime_r(&clock, &tm);
-
- value = tm.tm_year + 1900;
- }
-
- njs_set_number(&vm->retval, value);
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_date_prototype_get_utc_full_year(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
-{
- double value;
- time_t clock;
- struct tm tm;
-
- if (njs_slow_path(!njs_is_date(&args[0]))) {
- njs_type_error(vm, "cannot convert %s to date",
- njs_type_string(args[0].type));
-
- return NJS_ERROR;
- }
-
- value = njs_date(&args[0])->time;
-
- if (njs_fast_path(!isnan(value))) {
- clock = value / 1000;
- gmtime_r(&clock, &tm);
-
- value = tm.tm_year + 1900;
- }
-
- njs_set_number(&vm->retval, value);
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_date_prototype_get_month(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- double value;
- time_t clock;
- struct tm tm;
-
- if (njs_slow_path(!njs_is_date(&args[0]))) {
- njs_type_error(vm, "cannot convert %s to date",
- njs_type_string(args[0].type));
-
- return NJS_ERROR;
- }
-
- value = njs_date(&args[0])->time;
-
- if (njs_fast_path(!isnan(value))) {
- clock = value / 1000;
- localtime_r(&clock, &tm);
-
- value = tm.tm_mon;
- }
-
- njs_set_number(&vm->retval, value);
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_date_prototype_get_utc_month(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
+njs_date_prototype_get_field(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t magic)
{
- double value;
- time_t clock;
- struct tm tm;
-
- if (njs_slow_path(!njs_is_date(&args[0]))) {
- njs_type_error(vm, "cannot convert %s to date",
- njs_type_string(args[0].type));
-
- return NJS_ERROR;
- }
-
- value = njs_date(&args[0])->time;
-
- if (njs_fast_path(!isnan(value))) {
- clock = value / 1000;
-
- gmtime_r(&clock, &tm);
-
- value = tm.tm_mon;
- }
-
- njs_set_number(&vm->retval, value);
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_date_prototype_get_date(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- double value;
- time_t clock;
- struct tm tm;
-
- if (njs_slow_path(!njs_is_date(&args[0]))) {
- njs_type_error(vm, "cannot convert %s to date",
- njs_type_string(args[0].type));
-
- return NJS_ERROR;
- }
-
- value = njs_date(&args[0])->time;
-
- if (njs_fast_path(!isnan(value))) {
- clock = value / 1000;
- localtime_r(&clock, &tm);
-
- value = tm.tm_mday;
- }
-
More information about the nginx-devel
mailing list