[njs] Fixed Date.parse() with ISO-8601 format and UTC time offset.

Dmitry Volyntsev xeioex at nginx.com
Tue Jun 13 05:05:15 UTC 2023


details:   https://hg.nginx.org/njs/rev/ed4ff34dfc63
branches:  
changeset: 2154:ed4ff34dfc63
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Jun 12 22:04:04 2023 -0700
description:
Fixed Date.parse() with ISO-8601 format and UTC time offset.

diffstat:

 src/njs_date.c           |  65 +++++++++++++++++++++++++++++++++++++++--------
 src/test/njs_unit_test.c |  48 +++++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 11 deletions(-)

diffs (162 lines):

diff -r 803a5061b362 -r ed4ff34dfc63 src/njs_date.c
--- a/src/njs_date.c	Mon Jun 12 20:51:54 2023 -0700
+++ b/src/njs_date.c	Mon Jun 12 22:04:04 2023 -0700
@@ -493,11 +493,44 @@ njs_date_parse(njs_vm_t *vm, njs_value_t
 }
 
 
+static int64_t
+njs_date_utc_offset_parse(const u_char *start, const u_char *end)
+{
+    int64_t       utc_off, hour, min;
+    const u_char  *p;
+
+    if (njs_fast_path(start + 2 < end && (*start == '+' || *start == '-'))) {
+        p = njs_date_number_parse(&hour, start + 1, end, 2);
+        if (njs_slow_path(p == NULL || hour > 23)) {
+            return -1;
+        }
+
+        if (p < end && *p == ':') {
+            p++;
+        }
+
+        p = njs_date_number_parse(&min, p, end, 2);
+        if (njs_slow_path(p == NULL || min > 59)) {
+            return -1;
+        }
+
+        utc_off = hour * 60 + min;
+
+        if (*start == '-') {
+            utc_off = -utc_off;
+        }
+
+        return utc_off;
+    }
+
+    return -1;
+}
+
 static double
 njs_date_string_parse(njs_value_t *date)
 {
     size_t         ms_length;
-    int64_t        ext, skipped;
+    int64_t        ext, utc_off;
     njs_str_t      string;
     njs_bool_t     sign, week, utc;
     const u_char   *p, *next, *end;
@@ -616,25 +649,37 @@ njs_date_string_parse(njs_value_t *date)
 
         p++;
 
-        ms_length = (end - p < 3) ? end - p : 3;
+        for (ms_length = 0; p + ms_length < end; ms_length++) {
+            if (p[ms_length] < '0' || p[ms_length] > '9') {
+                break;
+            }
+        }
 
         p = njs_date_number_parse(&tm[NJS_DATE_MSEC], p, end, ms_length);
         if (njs_slow_path(p == NULL)) {
             return NAN;
         }
 
-        if (end > p) {
-            p = njs_date_number_parse(&skipped, p, end, end - p);
-            if (njs_slow_path(p == NULL)) {
-                return NAN;
-            }
-        }
-
         if (ms_length == 1) {
             tm[NJS_DATE_MSEC] *= 100;
 
         } else if (ms_length == 2) {
             tm[NJS_DATE_MSEC] *= 10;
+
+        } else if (ms_length >= 4) {
+            for (ms_length -= 3; ms_length > 0; ms_length--) {
+                tm[NJS_DATE_MSEC] /= 10;
+            }
+        }
+
+        if (p < end) {
+            utc_off = njs_date_utc_offset_parse(p, end);
+            if (njs_slow_path(utc_off == -1)) {
+                return NAN;
+            }
+
+            utc = 1;
+            tm[NJS_DATE_MSEC] += -utc_off * 60000;
         }
 
 done:
@@ -685,8 +730,6 @@ done:
 
         week = 0;
     }
-
-    return njs_make_date(tm, 0);
 }
 
 
diff -r 803a5061b362 -r ed4ff34dfc63 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Mon Jun 12 20:51:54 2023 -0700
+++ b/src/test/njs_unit_test.c	Mon Jun 12 22:04:04 2023 -0700
@@ -16172,6 +16172,54 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("Date.parse('2011-06-24T06:01:02.625Z')"),
       njs_str("1308895262625") },
 
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+00:00')"),
+      njs_str("1308895262625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+0000')"),
+      njs_str("1308895262625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+00:0')"),
+      njs_str("NaN") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+00:')"),
+      njs_str("NaN") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+00')"),
+      njs_str("NaN") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+0')"),
+      njs_str("NaN") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+')"),
+      njs_str("NaN") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625-01:15')"),
+      njs_str("1308899762625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625-01:60')"),
+      njs_str("NaN") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625-25:59')"),
+      njs_str("NaN") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+01:15')"),
+      njs_str("1308890762625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625-23:59')"),
+      njs_str("1308981602625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625+23:59')"),
+      njs_str("1308808922625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.6255Z')"),
+      njs_str("1308895262625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.62555Z')"),
+      njs_str("1308895262625") },
+
+    { njs_str("Date.parse('2011-06-24T06:01:02.625555Z')"),
+      njs_str("1308895262625") },
+
     { njs_str("Date.parse('2011-06-24T06:01:02.6255555Z')"),
       njs_str("1308895262625") },
 


More information about the nginx-devel mailing list