Created
March 2, 2012 08:08
-
-
Save nurse/1956692 to your computer and use it in GitHub Desktop.
Time.parse
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb | |
index cf7aad3..bff1d17 100644 | |
--- a/test/ruby/test_time.rb | |
+++ b/test/ruby/test_time.rb | |
@@ -744,4 +744,145 @@ class TestTime < Test::Unit::TestCase | |
end | |
assert_equal("Insecure: can't modify #{tc}", error.message, bug5036) | |
end | |
+ | |
+ def test_time_html5 | |
+ assert_equal(Time.utc(2000,1,31,12,34), Time.html5("2000-01-31T12:34Z")) | |
+ assert_equal(Time.utc(2000,1,31,12,34), Time.html5("2000-01-31 12:34Z")) | |
+ assert_equal(Time.utc(2000,1,31,12,34,56), Time.html5("2000-01-31T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-01-32T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,2,29,12,34,56), Time.html5("2000-02-29T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-02-30T12:34:56Z")} | |
+ assert_raise(ArgumentError){Time.html5("2001-02-29T12:34:56Z")} | |
+ assert_equal(Time.utc(2004,2,29,12,34,56), Time.html5("2004-02-29T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2100-02-29T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,3,31,12,34,56), Time.html5("2000-03-31T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-03-32T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,4,30,12,34,56), Time.html5("2000-04-30T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-04-31T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,5,31,12,34,56), Time.html5("2000-05-31T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-05-32T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,6,30,12,34,56), Time.html5("2000-06-30T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-06-31T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,7,31,12,34,56), Time.html5("2000-07-31T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-07-32T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,8,31,12,34,56), Time.html5("2000-08-31T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-08-32T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,9,30,12,34,56), Time.html5("2000-09-30T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-09-31T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,10,31,12,34,56), Time.html5("2000-10-31T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-10-32T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,11,30,12,34,56), Time.html5("2000-11-30T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-11-31T12:34:56Z")} | |
+ assert_equal(Time.utc(2000,12,31,12,34,56), Time.html5("2000-12-31T12:34:56Z")) | |
+ assert_raise(ArgumentError){Time.html5("2000-12-32T12:34:56Z")} | |
+ assert_equal(Time.new(2000,1,31,12,34,56,85500), Time.html5("2000-01-31T12:34:56+2345")) | |
+ assert_equal(Time.new(2000,1,31,12,34,56,85500), Time.html5("2000-01-31T12:34:56+23:45")) | |
+ assert_equal(Time.new(2000,1,31,12,34,56,-85500), Time.html5("2000-01-31T12:34:56-2345")) | |
+ assert_equal(Time.new(2000,1,31,12,34,56,-85500), Time.html5("2000-01-31T12:34:56-23:45")) | |
+ assert_equal(Time.new(2000,1,31,12,34,56,-85500), Time.html5("2000-01-31T12:34:56-23:45")) | |
+ assert_equal(Time.utc(18446744073709551616,1,31,12,34,56), Time.html5("18446744073709551616-01-31T12:34:56Z")) | |
+ assert_equal(Time.local(2000,12,31,12,34,56),Time.html5("2000-12-31T12:34:56")) | |
+ assert_raise(ArgumentError){Time.html5("2000-12-31T12:34:5")} | |
+ assert_raise(ArgumentError){Time.html5("2000-12-31T12:34:")} | |
+ assert_equal(Time.local(2000,12,31,12,34),Time.html5("2000-12-31T12:34")) | |
+ assert_raise(ArgumentError){Time.html5("2000-12-31T12:3")} | |
+ assert_raise(ArgumentError){Time.html5("2000-12-31T12:")} | |
+ assert_raise(ArgumentError){Time.html5("2000-12-31T12")} | |
+ assert_raise(ArgumentError){Time.html5("2000-12-31T1")} | |
+ assert_raise(ArgumentError){Time.html5("2000-12-31T")} | |
+ assert_equal(Time.local(2000,12,31), Time.html5("2000-12-31")) | |
+ assert_raise(ArgumentError){Time.html5("2000-12-")} | |
+ assert_raise(ArgumentError){Time.html5("2000-12")} | |
+ assert_raise(ArgumentError){Time.html5("2000-1")} | |
+ assert_raise(ArgumentError){Time.html5("2000-")} | |
+ assert_raise(ArgumentError){Time.html5("200")} | |
+ assert_raise(ArgumentError){Time.html5("20")} | |
+ assert_raise(ArgumentError){Time.html5("2")} | |
+ assert_raise(ArgumentError){Time.html5("")} | |
+ assert_equal(Time.utc(2005,12,31,23,59,59), Time.html5("2005-12-31T23:59:59Z")) | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:59:59+1")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:59:59+12")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:59:59+123")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:59:59+12345")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:59:599")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:59:59.1111Z")} | |
+ assert_raise(ArgumentError){Time.html5("-2005-12-31T23:59:59Z")} | |
+ assert_raise(ArgumentError){Time.html5("2005-13-31T23:59:59Z")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T24:59:59Z")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:60:59Z")} | |
+ assert_raise(ArgumentError){Time.html5("2005-12-31T23:59:60Z")} # HTML5 doesn't support leap seconds | |
+ end | |
+ | |
+ def test_time_parse_rfc6265_examples | |
+ # https://raw.github.com/abarth/http-state/master/tests/data/dates/examples.json | |
+ # https://raw.github.com/abarth/http-state/master/tests/data/dates/bsd-examples.json | |
+ assert_equal(Time.utc(1970, 1, 1, 0, 0, 0), Time.cookie("Thursday, 01-Jan-1970 00:00:00 GMT")) | |
+ assert_equal(Time.utc(1977, 4, 18, 22, 50, 13), Time.cookie("Mon, 18-Apr-1977 22:50:13 GMT")) | |
+ assert_equal(Time.utc(1977, 4, 18, 22, 50, 13), Time.cookie("Mon, 18-Apr-77 22:50:13 GMT")) | |
+ assert_equal(Time.utc(1995, 1, 1, 0, 0, 0), Time.cookie("Sun, 1-Jan-1995 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2003, 1, 1, 0, 0, 0), Time.cookie(" 1-Jan-2003 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2003, 1, 1, 0, 0, 0), Time.cookie(", 1-Jan-2003 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2003, 1, 1, 0, 0, 0), Time.cookie("1-Jan-2003 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2003, 1, 1, 0, 0, 0), Time.cookie("Wednes, 1-Januar-2003 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2003, 1, 1, 0, 0, 0), Time.cookie("Wednesday, 1-Jan-2003 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2007, 12, 10, 16, 32, 30), Time.cookie("Mon Dec 10 16:32:30 2007 GMT")) | |
+ assert_equal(Time.utc(2007, 12, 10, 17, 2, 24), Time.cookie("Mon, 10-Dec-2007 17:02:24 GMT")) | |
+ assert_equal(Time.utc(2007, 12, 10, 20, 35, 3), Time.cookie("Mon, 10-Dec-07 20:35:03 GMT")) | |
+ assert_equal(Time.utc(2007, 12, 12, 8, 44, 7), Time.cookie("Wed Dec 12 2007 08:44:07 GMT-0500 (EST)")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("22:50:12 Thu Apr 18 2007 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Partyday, 18 - Apri-07 22:50:12")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Partyday, 18- April-07 22:50:12")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Thu 22:50:12 Apr 18 2007 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Thu Apr 18 2007 22:50:12 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Thu Apr 18 2007 GMT 22:50:12")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Thu Apr 18 22:50:12 2007 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Thu Apr 22:50:12 18 2007 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("Wed,18-Apr-07 22:50:12 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("WillyWonka , 18-apr-07 22:50:12")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("WillyWonka , 18-Apr-07 22:50:12 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 18, 22, 50, 12), Time.cookie("WillyWonka , 18-Apr-07 22:50:12")) | |
+ assert_equal(Time.utc(2007, 4, 19, 16, 0, 0), Time.cookie("Thu, 19-Apr-2007 16:00:00 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 19, 16, 0, 0), Time.cookie("Thu, 19/Apr\\2007 16:00:00 GMT")) | |
+ assert_equal(Time.utc(2007, 4, 25, 21, 2, 13), Time.cookie("Wed, 25 Apr 2007 21:02:13 GMT")) | |
+ assert_equal(Time.utc(2009, 12, 10, 13, 57, 2), Time.cookie("Thu, 10 Dec 2009 13:57:2 GMT")) | |
+ assert_equal(Time.utc(2009, 12, 9, 16, 27, 23), Time.cookie("Wed, 09 Dec 2009 16:27:23 GMT")) | |
+ assert_equal(Time.utc(2010, 1, 1, 0, 0, 0), Time.cookie("Wednesday, 01-Jan-10 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2010, 1, 1, 0, 0, 0), Time.cookie("Wednesday, 01-Jan-10 0:0:00 GMT")) | |
+ assert_equal(Time.utc(2010, 1, 1, 1, 1, 50), Time.cookie("Fri, 1 Jan 2010 01:01:50 GMT")) | |
+ assert_equal(Time.utc(2012, 12, 8, 21, 24, 9), Time.cookie("Saturday, 8-Dec-2012 21:24:09 GMT")) | |
+ assert_equal(Time.utc(2012, 12, 9, 13, 42, 5), Time.cookie("Sun, 9 Dec 2012 13:42:05 GMT")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie('"Sat, 15-Apr-17\"21:01:22\"GMT"')) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("15 17 Apr 21:01:22")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("15 Apr 21:01:22 2017")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("15 April 2017 21:01:22")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("15-Sat, Apr 21:01:22 GMT 17")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("15-Sat, Apr 21:01:22 GMT 2017")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("15-Sat, Apr-17 21:01:22 GMT")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("2017 April 15 21:01:22")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Apr 15 17 21:01:22")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Apr 15 21:01:22 17")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 (hello there)")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 -0400")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 11:22:33")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 DST")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 GMT BLAH")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 GMT")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 GMT-0400 (EDT)")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 GMT-0400")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22 GMT-2")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 21:01:22")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 ::00 21:01:22")) | |
+ assert_equal(Time.utc(2017, 4, 15, 21, 1, 22), Time.cookie("Sat, 15-Apr-17 boink:z 21:01:22")) | |
+ assert_equal(Time.utc(2020, 1, 1, 0, 0, 0), Time.cookie("Wed, 1 Jan 2020 00:00:00 GMT")) | |
+ assert_equal(Time.utc(2037, 12, 31, 23, 55, 55), Time.cookie("Thu, 31 Dec 23:55:55 2037 GMT")) | |
+ assert_raise(ArgumentError){ Time.cookie("98 April 17 21:01:22") } | |
+ assert_raise(ArgumentError){ Time.cookie("IAintNoDateFool") } | |
+ assert_raise(ArgumentError){ Time.cookie("Mon, 01-Jan-2011 00: 00:00 GMT") } | |
+ assert_raise(ArgumentError){ Time.cookie("Sat, 15-Apr-17 91:22:33 21:01:22") } | |
+ assert_raise(ArgumentError){ Time.cookie("Thu, 012-Aug-2008 20:49:07 GMT") } | |
+ assert_raise(ArgumentError){ Time.cookie("Thu, 12-Aug-2007 20:61:99999999999 GMT") } | |
+ assert_raise(ArgumentError){ Time.cookie("Thu, 12-Aug-31841 20:49:07 GMT") } | |
+ assert_raise(ArgumentError){ Time.cookie("Thu, 12-Aug-9999999999 20:49:07 GMT") } | |
+ assert_raise(ArgumentError){ Time.cookie("Thu, 999999999999-Aug-2007 20:49:07 GMT") } | |
+ end | |
end | |
diff --git a/time.c b/time.c | |
index 5748c14..40a1b1a 100644 | |
--- a/time.c | |
+++ b/time.c | |
@@ -3152,6 +3152,357 @@ time_s_mktime(int argc, VALUE *argv, VALUE klass) | |
return time_utc_or_local(argc, argv, FALSE, klass); | |
} | |
+#define RFC6265_DELIMITER_P(p) ((p) == 9 || \ | |
+ (0x20 <= (p) && (p) <= 0x2F) || \ | |
+ (0x3B <= (p) && (p) <= 0x40) || \ | |
+ (0x5B <= (p) && (p) <= 0x60) || \ | |
+ (0x7B <= (p) && (p) <= 0x7E)) | |
+ | |
+/* | |
+ * HTML5 datetime | |
+ * http://dev.w3.org/html5/spec/the-time-element.html#the-time-element | |
+ * | |
+ * * valid date string | |
+ * * valid local date and time string | |
+ * * valid global date and time string | |
+ */ | |
+static VALUE | |
+parse_html5(VALUE klass, const char *p, const char *e) | |
+{ | |
+ const char *q; | |
+ int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, msec = -1; | |
+ struct vtm vtm; | |
+ VALUE offset = FALSE; | |
+ | |
+ for (q = p; ISDIGIT(*p); p++) { | |
+ year *= 10; | |
+ year += *p - '0'; | |
+ if (p - q > 9) { | |
+ /* too big for 32bit int */ | |
+ vtm.year = rb_cstr_to_inum(q, 10, FALSE); | |
+ for (; ISDIGIT(*p); p++); | |
+ goto after_year; | |
+ } | |
+ } | |
+ if (p - q < 4) goto fail; | |
+ vtm.year = INT2FIX(year); | |
+ | |
+after_year: | |
+ if (*p++ != '-' || !ISDIGIT(p[0]) || !ISDIGIT(p[1])) goto fail; | |
+ mon = p[0] * 10 + p[1] - '0' * 11; | |
+ if (mon < 1 || 12 < mon) goto fail; | |
+ p += 2; | |
+ | |
+ if (*p++ != '-' || !ISDIGIT(p[0]) || !ISDIGIT(p[1])) goto fail; | |
+ day = p[0] * 10 + p[1] - '0' * 11; | |
+ if (day <= 28); | |
+ else if (mon == 2) { | |
+ if (day == 29 && year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); | |
+ else goto fail; | |
+ } | |
+ else if (mon == 4 || mon == 6 || mon == 9 || mon == 11) { | |
+ if (day > 30) goto fail; | |
+ } | |
+ else if (day > 31) goto fail; | |
+ p += 2; | |
+ | |
+ if (!*p) goto finish; | |
+ | |
+ if (*p != 'T' && *p != ' ') goto fail; | |
+ p++; | |
+ | |
+ if (!ISDIGIT(p[0]) || !ISDIGIT(p[1])) goto fail; | |
+ hour = p[0] * 10 + p[1] - '0' * 11; | |
+ if (23 < hour) goto fail; | |
+ p += 2; | |
+ | |
+ if (*p++ != ':' || !ISDIGIT(p[0]) || !ISDIGIT(p[1])) goto fail; | |
+ min = p[0] * 10 + p[1] - '0' * 11; | |
+ if (59 < min) goto fail; | |
+ p += 2; | |
+ | |
+ if (*p == ':') { | |
+ if (!ISDIGIT(p[1]) || !ISDIGIT(p[2])) goto fail; | |
+ sec = p[1] * 10 + p[2] - '0' * 11; | |
+ if (59 < sec) goto fail; | |
+ p += 3; | |
+ | |
+ if (*p == '.') { | |
+ p++; | |
+ if (ISDIGIT(*p)) { | |
+ msec = *p++ * 100 - '0' * 100; | |
+ if (ISDIGIT(*p)) { | |
+ msec += *p++ * 10 - '0' * 10; | |
+ if (ISDIGIT(*p)) { | |
+ msec += *p++ - '0'; | |
+ } | |
+ } | |
+ } | |
+ else goto fail; | |
+ } | |
+ } | |
+ | |
+ if (!*p) goto finish; | |
+ | |
+ if (*p == 'Z') { | |
+ p++; | |
+ offset = Qnil; | |
+ } | |
+ else { | |
+ int sign, h, m; | |
+ if ((p[0] != '-' && *p != '+') || !ISDIGIT(p[1]) || !ISDIGIT(p[2])) goto fail; | |
+ sign = 0x2C - p[0]; | |
+ h = p[1] * 10 + p[2] - '0' * 11; | |
+ if (h > 23) return Qnil; | |
+ p += 3; | |
+ if (*p == ':') p++; | |
+ if (!ISDIGIT(p[0]) || !ISDIGIT(p[1])) goto fail; | |
+ m = p[0] * 10 + p[1] - '0' * 11; | |
+ if (m > 60) return Qnil; | |
+ p += 2; | |
+ offset = INT2FIX(sign * (h*60+m) * 60); | |
+ } | |
+ | |
+ if (*p) goto fail; | |
+ | |
+finish: | |
+ vtm.mon = mon; | |
+ vtm.mday = day; | |
+ vtm.hour = hour; | |
+ vtm.min = min; | |
+ vtm.sec = sec; | |
+ vtm.subsecx = (msec == -1) ? INT2FIX(0) : quo(INT2FIX(msec),INT2FIX(1000)); | |
+ vtm.wday = 0; | |
+ vtm.yday = 0; | |
+ vtm.isdst = 0; | |
+ vtm.zone = ""; | |
+ | |
+ if (!offset) { | |
+ /* local */ | |
+ return time_new_timew(klass, timelocalw(&vtm)); | |
+ } | |
+ else if (NIL_P(offset)) { | |
+ /* UTC */ | |
+ return time_new_timew(klass, timegmw(&vtm)); | |
+ } | |
+ else { | |
+ /* with offset */ | |
+ vtm.utc_offset = offset; | |
+ vtm_add_offset(&vtm, neg(offset)); | |
+ vtm.utc_offset = Qnil; | |
+ return time_set_utc_offset(time_new_timew(klass, timegmw(&vtm)), offset); | |
+ } | |
+ | |
+fail: | |
+ return Qnil; | |
+} | |
+ | |
+#define ICCMP(c, i) (((c)&223) == ((i)&223)) | |
+ | |
+/* | |
+ * Cookie Dates | |
+ * http://tools.ietf.org/html/rfc6265 | |
+ */ | |
+static VALUE | |
+parse_rfc6265(VALUE klass, const char *p, const char *e) | |
+{ | |
+ int found_time_p = FALSE; | |
+ int found_day_of_month_p = FALSE; | |
+ int found_month_p = FALSE; | |
+ int found_year_p = FALSE; | |
+ int year, mon, day, hour, min, sec; | |
+ | |
+ while (p < e) { | |
+ if (ISDIGIT(*p)) { | |
+ int len; | |
+ int tmp = *p - '0'; | |
+ const char *q = p; | |
+ while (ISDIGIT(*++p)) { | |
+ tmp *= 10; | |
+ tmp += *p - '0'; | |
+ } | |
+ len = p - q; | |
+ switch (len) { | |
+ case 1: | |
+ case 2: | |
+ if (!found_time_p && *p == ':') { | |
+ p++; | |
+ hour = tmp; | |
+ if (ISDIGIT(*p)) { | |
+ min = *p++ - '0'; | |
+ if (ISDIGIT(*p)) { | |
+ min *= 10; | |
+ min += *p++ - '0'; | |
+ } | |
+ if (*p++ == ':' && ISDIGIT(*p)) { | |
+ sec = *p++ - '0'; | |
+ if (ISDIGIT(*p)) { | |
+ sec *= 10; | |
+ sec += *p++ - '0'; | |
+ } | |
+ if (!*p || RFC6265_DELIMITER_P(*p)) { | |
+ found_time_p = TRUE; | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ if (!found_day_of_month_p) { | |
+ day = tmp; | |
+ found_day_of_month_p = TRUE; | |
+ break; | |
+ } | |
+ case 3: | |
+ case 4: | |
+ if (len >= 2 && !found_year_p) { | |
+ year = tmp; | |
+ found_year_p = TRUE; | |
+ break; | |
+ } | |
+ break; | |
+ } | |
+ } | |
+ else if (!found_month_p) { | |
+ switch (*p&223) { | |
+ case 'A': | |
+ if (ICCMP(p[1], 'P') && ICCMP(p[2], 'R')) { | |
+ mon = 4; | |
+ goto found_month; | |
+ } | |
+ else if (ICCMP(p[1], 'U') && ICCMP(p[2], 'G')) { | |
+ mon = 8; | |
+ goto found_month; | |
+ } | |
+ break; | |
+ case 'D': | |
+ if (ICCMP(p[1], 'E') && ICCMP(p[2], 'C')) { | |
+ mon = 12; | |
+ goto found_month; | |
+ } | |
+ break; | |
+ case 'F': | |
+ if (ICCMP(p[1], 'E') && ICCMP(p[2], 'B')) { | |
+ mon = 2; | |
+ goto found_month; | |
+ } | |
+ break; | |
+ case 'J': | |
+ if (ICCMP(p[1], 'A')) { | |
+ if (ICCMP(p[2], 'N')) { | |
+ mon = 1; | |
+ goto found_month; | |
+ } | |
+ } | |
+ else if ICCMP(p[1], 'U') { | |
+ if ICCMP(p[2], 'L') { | |
+ mon = 7; | |
+ goto found_month; | |
+ } | |
+ else if ICCMP(p[2], 'N') { | |
+ mon = 6; | |
+ goto found_month; | |
+ } | |
+ } | |
+ break; | |
+ case 'M': | |
+ if (ICCMP(p[1], 'A') && ICCMP(p[2], 'Y')) { | |
+ mon = 5; | |
+ goto found_month; | |
+ } | |
+ break; | |
+ case 'N': | |
+ if (ICCMP(p[1], 'O') && ICCMP(p[2], 'V')) { | |
+ mon = 11; | |
+ goto found_month; | |
+ } | |
+ break; | |
+ case 'O': | |
+ if (ICCMP(p[1], 'C') && ICCMP(p[2], 'T')) { | |
+ mon = 10; | |
+ goto found_month; | |
+ } | |
+ break; | |
+ case 'S': | |
+ if (ICCMP(p[1], 'E') && ICCMP(p[2], 'P')) { | |
+ mon = 9; | |
+found_month: | |
+ found_month_p = TRUE; | |
+ p += 3; | |
+ } | |
+ break; | |
+ } | |
+ } | |
+ | |
+ for (; p < e && !RFC6265_DELIMITER_P(*p); p++); | |
+ for (; RFC6265_DELIMITER_P(*p); p++); | |
+ } | |
+ | |
+ if (found_time_p && found_day_of_month_p && found_month_p && found_year_p) { | |
+ struct vtm vtm; | |
+ if (year < 70) | |
+ year += 2000; | |
+ else if (year < 100) | |
+ year += 1900; | |
+ if (day < 1 || 31 < day || year < 1601 || hour > 23 || min > 59 || sec > 59) | |
+ return Qnil; | |
+ vtm.year = INT2FIX(year); | |
+ vtm.mon = mon; | |
+ vtm.mday = day; | |
+ vtm.hour = hour; | |
+ vtm.min = min; | |
+ vtm.sec = sec; | |
+ vtm.subsecx = INT2FIX(0); | |
+ vtm.utc_offset = Qnil; | |
+ vtm.wday = 0; | |
+ vtm.yday = 0; | |
+ vtm.isdst = 0; | |
+ vtm.zone = ""; | |
+ return time_gmtime(time_new_timew(klass, timegmw(&vtm))); | |
+ } | |
+ | |
+ /* | |
+ fprintf(stderr, "%d %d %d %d %04d-%02d-%02d %02d:%02d:%02d\n", | |
+ found_time_p, found_day_of_month_p, found_month_p, found_year_p, | |
+ year, mon, day, hour, min, sec);// */ | |
+ return Qnil; | |
+} | |
+ | |
+/* call-seq: | |
+ * Time.html5(string) -> time | |
+ * | |
+ * Parse a string and create a time object. | |
+ * | |
+ * HTML5 Dates and Times + negative year | |
+ */ | |
+ | |
+static VALUE | |
+time_s_html5(VALUE klass, VALUE str) | |
+{ | |
+ const char *p = StringValueCStr(str); | |
+ const char *e = RSTRING_END(str); | |
+ VALUE v = parse_html5(klass, p, e); | |
+ if (NIL_P(v)) rb_raise(rb_eArgError, "cannot find valid time information in '%s'", p); | |
+ return v; | |
+} | |
+ | |
+/* call-seq: | |
+ * Time.cookie(string) -> time | |
+ * | |
+ * Parse a string and create a time object. | |
+ * | |
+ * RFC6265 HTTP State Management Mechanism, a.k.a. Cookie Dates | |
+ */ | |
+ | |
+static VALUE | |
+time_s_cookie(VALUE klass, VALUE str) | |
+{ | |
+ const char *p = StringValueCStr(str); | |
+ const char *e = RSTRING_END(str); | |
+ VALUE v = parse_rfc6265(klass, p, e); | |
+ if (NIL_P(v)) rb_raise(rb_eArgError, "cannot find valid time information in '%s'", p); | |
+ return v; | |
+} | |
+ | |
/* | |
* call-seq: | |
* time.to_i -> int | |
@@ -4956,6 +5307,8 @@ Init_Time(void) | |
rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1); | |
rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1); | |
rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1); | |
+ rb_define_singleton_method(rb_cTime, "html5", time_s_html5, 1); | |
+ rb_define_singleton_method(rb_cTime, "cookie", time_s_cookie, 1); | |
rb_define_method(rb_cTime, "to_i", time_to_i, 0); | |
rb_define_method(rb_cTime, "to_f", time_to_f, 0); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment