From ec01a8813ffe941220a6c77ee6f57a29f391501b Mon Sep 17 00:00:00 2001 From: tadf Date: Sat, 16 Apr 2011 12:58:28 +0000 Subject: * ext/date/date_core.c: replacement of implementation of _strptime. [experimental] * ext/date/date_strptime.c: new. * ext/date/lib/date/format.rb: removed ruby version of _strptime. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31295 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/date/date_core.c | 86 ++++++ ext/date/date_strptime.c | 695 ++++++++++++++++++++++++++++++++++++++++++++ ext/date/lib/date/format.rb | 219 -------------- 3 files changed, 781 insertions(+), 219 deletions(-) create mode 100644 ext/date/date_strptime.c (limited to 'ext/date') diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 2a710d5f4d..eb0e45c9e6 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -1356,6 +1356,77 @@ date_s_today(int argc, VALUE *argv, VALUE klass) } } +VALUE +zone_to_diff(VALUE s) +{ + return rb_funcall(cDate, rb_intern("zone_to_diff"), 1, s); +} + +VALUE +date__strptime(const char *str, size_t slen, + const char *fmt, size_t flen, VALUE hash); + +static VALUE +date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, + const char *default_fmt) +{ + VALUE vstr, vfmt, hash; + const char *str, *fmt; + size_t slen, flen; + + rb_scan_args(argc, argv, "11", &vstr, &vfmt); + + StringValue(vstr); + if (!rb_enc_str_asciicompat_p(vstr)) + rb_raise(rb_eArgError, + "string should have ASCII compatible encoding"); + str = RSTRING_PTR(vstr); + slen = RSTRING_LEN(vstr); + if (argc < 2) { + fmt = default_fmt; + flen = strlen(default_fmt); + } + else { + StringValue(vfmt); + if (!rb_enc_str_asciicompat_p(vfmt)) + rb_raise(rb_eArgError, + "format should have ASCII compatible encoding"); + fmt = RSTRING_PTR(vfmt); + flen = RSTRING_LEN(vfmt); + } + hash = rb_hash_new(); + if (NIL_P(date__strptime(str, slen, fmt, flen, hash))) + return Qnil; + + { + VALUE zone = rb_hash_aref(hash, ID2SYM(rb_intern("zone"))); + VALUE left = rb_hash_aref(hash, ID2SYM(rb_intern("leftover"))); + + if (!NIL_P(zone)) { + rb_enc_copy(zone, vstr); + rb_hash_aset(hash, ID2SYM(rb_intern("zone")), zone); + } + if (!NIL_P(left)) { + rb_enc_copy(left, vstr); + rb_hash_aset(hash, ID2SYM(rb_intern("leftover")), left); + } + } + + return hash; +} + +/* + * call-seq: + * Date._strftime(string, [format="%F"]) + * + * Return a hash of parsed elements. + */ +static VALUE +date_s__strptime(int argc, VALUE *argv, VALUE klass) +{ + return date_s__strptime_internal(argc, argv, klass, "%F"); +} + /* * call-seq: * d.ajd @@ -3086,6 +3157,18 @@ datetime_s_now(int argc, VALUE *argv, VALUE klass) } } +/* + * call-seq: + * DateTime._strftime(string, [format="%FT%T%z"]) + * + * Return a hash of parsed elements. + */ +static VALUE +datetime_s__strptime(int argc, VALUE *argv, VALUE klass) +{ + return date_s__strptime_internal(argc, argv, klass, "%FT%T%z"); +} + /* * call-seq: * dt.ajd @@ -4376,6 +4459,7 @@ Init_date_core(void) rb_define_singleton_method(cDate, "new", date_s_civil, -1); rb_define_singleton_method(cDate, "commercial", date_s_commercial, -1); rb_define_singleton_method(cDate, "today", date_s_today, -1); + rb_define_singleton_method(cDate, "_strptime", date_s__strptime, -1); rb_define_method(cDate, "ajd", d_lite_ajd, 0); rb_define_method(cDate, "amjd", d_lite_amjd, 0); @@ -4451,6 +4535,8 @@ Init_date_core(void) rb_define_singleton_method(cDateTime, "commercial", datetime_s_commercial, -1); rb_define_singleton_method(cDateTime, "now", datetime_s_now, -1); + rb_define_singleton_method(cDateTime, "_strptime", + datetime_s__strptime, -1); rb_define_method(cDateTime, "ajd", dt_lite_ajd, 0); rb_define_method(cDateTime, "amjd", dt_lite_amjd, 0); diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c new file mode 100644 index 0000000000..27f0893efc --- /dev/null +++ b/ext/date/date_strptime.c @@ -0,0 +1,695 @@ +/* + date_strptime.c: Coded by Tadayoshi Funaba 2011 +*/ + +#include "ruby.h" +#include "ruby/encoding.h" +#include "ruby/re.h" +#include + +static const char *day_names[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" +}; + +static const char *month_names[] = { + "January", "February", "March", "April", + "May", "June", "July", "August", "September", + "October", "November", "December", + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static const char *merid_names[] = { + "am", "pm", + "a.m.", "p.m." +}; + +static const char *extz_pats[] = { + ":z", + "::z", + ":::z" +}; + +#define sizeof_array(o) (sizeof o / sizeof o[0]) + +#define f_negate(x) rb_funcall(x, rb_intern("-@"), 0) +#define f_add(x,y) rb_funcall(x, '+', 1, y) +#define f_sub(x,y) rb_funcall(x, '-', 1, y) +#define f_mul(x,y) rb_funcall(x, '*', 1, y) +#define f_div(x,y) rb_funcall(x, '/', 1, y) +#define f_mod(x,y) rb_funcall(x, '%', 1, y) +#define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y) + +#define f_lt_p(x,y) rb_funcall(x, '<', 1, y) +#define f_gt_p(x,y) rb_funcall(x, '>', 1, y) +#define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y) +#define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y) + +#define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s) +#define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i) +#define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i) + +static int +num_pattern_p(const char *s) +{ + if (isdigit(*s)) + return 1; + if (*s == '%') { + s++; + if (*s == 'E' || *s == 'O') + s++; + if (*s && + (strchr("CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy", *s) || isdigit(*s))) + return 1; + } + return 0; +} + +#define NUM_PATTERN_P() num_pattern_p(&fmt[fi + 1]) + +static long +read_digits(const char *s, VALUE *n, size_t width) +{ + size_t l; + + l = strspn(s, "0123456789"); + + if (l == 0) + return 0; + + if (width < l) + l = width; + + if ((4 * l * sizeof(char)) <= (sizeof(long)*CHAR_BIT)) { + const char *os = s; + long v; + + v = 0; + while ((size_t)(s - os) < l) { + v *= 10; + v += *s - '0'; + s++; + } + if (os == s) + return 0; + *n = LONG2NUM(v); + return l; + } + else { + char *s2 = ALLOCA_N(char, l + 1); + memcpy(s2, s, l); + s2[l] = '\0'; + *n = rb_cstr_to_inum(s2, 10, 0); + return l; + } +} + +#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v) +#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k))) +#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k))) + +#define fail() \ +{ \ + set_hash("_fail", Qtrue); \ + return 0; \ +} + +#define fail_p() (!NIL_P(ref_hash("_fail"))) + +#define READ_DIGITS(n,w) \ +{ \ + size_t l; \ + l = read_digits(&str[si], &n, w); \ + if (l == 0) \ + fail(); \ + si += l; \ +} + +#define READ_DIGITS_MAX(n) READ_DIGITS(n, LONG_MAX) + +static int +valid_range_p(VALUE v, int a, int b) +{ + if (FIXNUM_P(v)) { + int vi = FIX2INT(v); + return !(vi < a || vi > b); + } + return !(f_lt_p(v, INT2NUM(a)) || f_gt_p(v, INT2NUM(b))); +} + +#define recur(fmt) \ +{ \ + size_t l; \ + l = date__strptime_internal(&str[si], slen - si, \ + fmt, sizeof fmt - 1, hash); \ + if (fail_p()) \ + return 0; \ + si += l; \ +} + +static size_t +date__strptime_internal(const char *str, size_t slen, + const char *fmt, size_t flen, VALUE hash) +{ + size_t si, fi; + int c; + + si = fi = 0; + + while (fi < flen) { + + switch (fmt[fi]) { + case '%': + + again: + fi++; + c = fmt[fi]; + + switch (c) { + case 'E': + if (fmt[fi + 1] && strchr("cCxXyY", fmt[fi + 1])) + goto again; + fi--; + goto ordinal; + case 'O': + if (fmt[fi + 1] && strchr("deHImMSuUVwWy", fmt[fi + 1])) + goto again; + fi--; + goto ordinal; + case ':': + { + int i; + + for (i = 0; i < (int)sizeof_array(extz_pats); i++) + if (strncmp(extz_pats[i], &fmt[fi], + strlen(extz_pats[i])) == 0) { + fi += i; + goto again; + } + fail(); + } + + case 'A': + case 'a': + { + int i; + + for (i = 0; i < (int)sizeof_array(day_names); i++) { + size_t l = strlen(day_names[i]); + if (strncasecmp(day_names[i], &str[si], l) == 0) { + si += l; + set_hash("wday", INT2FIX(i % 7)); + goto matched; + } + } + fail(); + } + case 'B': + case 'b': + case 'h': + { + int i; + + for (i = 0; i < (int)sizeof_array(month_names); i++) { + size_t l = strlen(month_names[i]); + if (strncasecmp(month_names[i], &str[si], l) == 0) { + si += l; + set_hash("mon", INT2FIX((i % 12) + 1)); + goto matched; + } + } + fail(); + } + + case 'C': + { + VALUE n; + + if (NUM_PATTERN_P()) + READ_DIGITS(n, 2) + else + READ_DIGITS_MAX(n) + set_hash("_cent", n); + goto matched; + } + + case 'c': + recur("%a %b %e %H:%M:%S %Y"); + goto matched; + + case 'D': + recur("%m/%d/%y"); + goto matched; + + case 'd': + case 'e': + { + VALUE n; + + if (str[si] == ' ') { + si++; + READ_DIGITS(n, 1); + } else { + READ_DIGITS(n, 2); + } + if (!valid_range_p(n, 1, 31)) + fail(); + set_hash("mday", n); + goto matched; + } + + case 'F': + recur("%Y-%m-%d"); + goto matched; + + case 'G': + { + VALUE n; + + if (NUM_PATTERN_P()) + READ_DIGITS(n, 4) + else + READ_DIGITS_MAX(n) + set_hash("cwyear", n); + goto matched; + } + + case 'g': + { + VALUE n; + + READ_DIGITS(n, 2); + if (!valid_range_p(n, 0, 99)) + fail(); + set_hash("cwyear",n); + set_hash("_cent", + INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); + goto matched; + } + + case 'H': + case 'k': + { + VALUE n; + + if (str[si] == ' ') { + si++; + READ_DIGITS(n, 1); + } else { + READ_DIGITS(n, 2); + } + if (!valid_range_p(n, 0, 24)) + fail(); + set_hash("hour", n); + goto matched; + } + + case 'I': + case 'l': + { + VALUE n; + + if (str[si] == ' ') { + si++; + READ_DIGITS(n, 1); + } else { + READ_DIGITS(n, 2); + } + if (!valid_range_p(n, 1, 12)) + fail(); + set_hash("hour", n); + goto matched; + } + + case 'j': + { + VALUE n; + + READ_DIGITS(n, 3); + if (!valid_range_p(n, 1, 366)) + fail(); + set_hash("yday", n); + goto matched; + } + + case 'L': + case 'N': + { + VALUE n; + int sign = 1; + size_t osi; + + if (str[si] == '-' || str[si] == '+') { + if (str[si] == '-') + sign = -1; + si++; + } + osi = si; + if (NUM_PATTERN_P()) + READ_DIGITS(n, c == 'L' ? 3 : 9) + else + READ_DIGITS_MAX(n) + if (sign == -1) + n = f_negate(n); + set_hash("sec_fraction", + rb_rational_new2(n, + f_expt(INT2FIX(10), + ULONG2NUM(si - osi)))); + goto matched; + } + + case 'M': + { + VALUE n; + + READ_DIGITS(n, 2); + if (!valid_range_p(n, 0, 59)) + fail(); + set_hash("min", n); + goto matched; + } + + case 'm': + { + VALUE n; + + READ_DIGITS(n, 2); + if (!valid_range_p(n, 1, 12)) + fail(); + set_hash("mon", n); + goto matched; + } + + case 'n': + case 't': + recur(" "); + goto matched; + + case 'P': + case 'p': + { + int i; + + for (i = 0; i < 4; i++) { + size_t l = strlen(merid_names[i]); + if (strncasecmp(merid_names[i], &str[si], l) == 0) { + si += l; + set_hash("_merid", INT2FIX((i % 2) == 0 ? 0 : 12)); + goto matched; + } + } + fail(); + } + + case 'Q': + { + VALUE n; + int sign = 1; + + if (str[si] == '-') { + sign = -1; + si++; + } + READ_DIGITS_MAX(n); + if (sign == -1) + n = f_negate(n); + set_hash("seconds", + rb_rational_new2(n, + f_expt(INT2FIX(10), + INT2FIX(3)))); + goto matched; + } + + case 'R': + recur("%H:%M"); + goto matched; + + case 'r': + recur("%I:%M:%S %p"); + goto matched; + + case 'S': + { + VALUE n; + + READ_DIGITS(n, 2); + if (!valid_range_p(n, 0, 60)) + fail(); + set_hash("sec", n); + goto matched; + } + + case 's': + { + VALUE n; + int sign = 1; + + if (str[si] == '-') { + sign = -1; + si++; + } + READ_DIGITS_MAX(n); + if (sign == -1) + n = f_negate(n); + set_hash("seconds", n); + goto matched; + } + + case 'T': + recur("%H:%M:%S"); + goto matched; + + case 'U': + case 'W': + { + VALUE n; + + READ_DIGITS(n, 2); + if (!valid_range_p(n, 0, 53)) + fail(); + set_hash(c == 'U' ? "wnum0" : "wnum1", n); + goto matched; + } + + case 'u': + { + VALUE n; + + READ_DIGITS(n, 1); + if (!valid_range_p(n, 1, 7)) + fail(); + set_hash("cwday", n); + goto matched; + } + + case 'V': + { + VALUE n; + + READ_DIGITS(n, 2); + if (!valid_range_p(n, 1, 53)) + fail(); + set_hash("cweek", n); + goto matched; + } + + case 'v': + recur("%e-%b-%Y"); + goto matched; + + case 'w': + { + VALUE n; + + READ_DIGITS(n, 1); + if (!valid_range_p(n, 0, 6)) + fail(); + set_hash("wday", n); + goto matched; + } + + case 'X': + recur("%H:%M:%S"); + goto matched; + + case 'x': + recur("%m/%d/%y"); + goto matched; + + case 'Y': + { + VALUE n; + int sign = 1; + + if (str[si] == '-' || str[si] == '+') { + if (str[si] == '-') + sign = -1; + si++; + } + if (NUM_PATTERN_P()) + READ_DIGITS(n, 4) + else + READ_DIGITS_MAX(n) + if (sign == -1) + n = f_negate(n); + set_hash("year", n); + goto matched; + } + + case 'y': + { + VALUE n; + int sign = 1; + + READ_DIGITS(n, 2); + if (!valid_range_p(n, 0, 99)) + fail(); + if (sign == -1) + n = f_negate(n); + set_hash("year", n); + set_hash("_cent", + INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); + goto matched; + } + + + case 'Z': + case 'z': + { + static const char pat_source[] = + "\\A(" + "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?" + "|[[:alpha:].\\s]+(?:standard|daylight)\\s+time\\b" + "|[[:alpha:]]+(?:\\s+dst)?\\b" + ")"; + static VALUE pat = Qnil; + VALUE m, b; + VALUE zone_to_diff(VALUE s); + + if (NIL_P(pat)) { + pat = rb_reg_new(pat_source, sizeof pat_source - 1, + ONIG_OPTION_IGNORECASE); + rb_gc_register_mark_object(pat); + } + + b = rb_backref_get(); + m = f_match(pat, rb_usascii_str_new2(&str[si])); + + if (!NIL_P(m)) { + VALUE s, l, o; + + s = f_aref(m, INT2FIX(1)); + l = f_end(m, INT2FIX(0)); + o = zone_to_diff(s); + si += NUM2LONG(l); + set_hash("zone", s); + set_hash("offset", o); + rb_backref_set(b); + goto matched; + } + rb_backref_set(b); + fail(); + } + + case '%': + if (str[si] != '%') + fail(); + si++; + goto matched; + + case '+': + recur("%a %b %e %H:%M:%S %Z %Y"); + goto matched; + + default: + if (str[si] != '%') + fail(); + si++; + if (fi < flen) + if (str[si] != fmt[fi]) + fail(); + si++; + goto matched; + } + case ' ': + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + while (isspace(str[si])) + si++; + fi++; + break; + default: + ordinal: + if (str[si] != fmt[fi]) + fail(); + si++; + fi++; + break; + matched: + fi++; + break; + } + } + + { + VALUE s; + + if (slen > si) { + s = rb_usascii_str_new(&str[si], slen - si); + set_hash("leftover", s); + } + } + + return si; +} + +VALUE +date__strptime(const char *str, size_t slen, + const char *fmt, size_t flen, VALUE hash) +{ + VALUE cent, merid; + + date__strptime_internal(str, slen, fmt, flen, hash); + + if (fail_p()) + return Qnil; + + cent = ref_hash("_cent"); + if (!NIL_P(cent)) { + VALUE year; + + year = ref_hash("cwyear"); + if (!NIL_P(year)) + set_hash("cwyear", f_add(year, f_mul(cent, INT2FIX(100)))); + year = ref_hash("year"); + if (!NIL_P(year)) + set_hash("year", f_add(year, f_mul(cent, INT2FIX(100)))); + del_hash("_cent"); + } + + merid = ref_hash("_merid"); + if (!NIL_P(merid)) { + VALUE hour; + + hour = ref_hash("hour"); + if (!NIL_P(hour)) { + hour = f_mod(hour, INT2FIX(12)); + set_hash("hour", f_add(hour, merid)); + } + del_hash("_merid"); + } + + return hash; +} + +/* +Local variables: +c-file-style: "ruby" +End: +*/ diff --git a/ext/date/lib/date/format.rb b/ext/date/lib/date/format.rb index d38525b7e3..00fcb363ef 100644 --- a/ext/date/lib/date/format.rb +++ b/ext/date/lib/date/format.rb @@ -179,221 +179,6 @@ class Date end =end - def self.num_pattern? (s) # :nodoc: - /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s - end - - private_class_method :num_pattern? - - def self._strptime_i(str, fmt, e) # :nodoc: - fmt.scan(/%([EO]?(?::{1,3}z|.))|(.)/m) do |s, c| - a = $& - if s - case s - when 'A', 'a' - return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') || - str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '') - val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase] - return unless val - e.wday = val - when 'B', 'b', 'h' - return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') || - str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '') - val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase] - return unless val - e.mon = val - when 'C', 'EC' - return unless str.sub!(if num_pattern?($') - then /\A([-+]?\d{1,2})/ - else /\A([-+]?\d{1,})/ - end, '') - val = $1.to_i - e._cent = val - when 'c', 'Ec' - return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e) - when 'D' - return unless _strptime_i(str, '%m/%d/%y', e) - when 'd', 'e', 'Od', 'Oe' - return unless str.sub!(/\A( \d|\d{1,2})/, '') - val = $1.to_i - return unless (1..31) === val - e.mday = val - when 'F' - return unless _strptime_i(str, '%Y-%m-%d', e) - when 'G' - return unless str.sub!(if num_pattern?($') - then /\A([-+]?\d{1,4})/ - else /\A([-+]?\d{1,})/ - end, '') - val = $1.to_i - e.cwyear = val - when 'g' - return unless str.sub!(/\A(\d{1,2})/, '') - val = $1.to_i - return unless (0..99) === val - e.cwyear = val - e._cent ||= if val >= 69 then 19 else 20 end - when 'H', 'k', 'OH' - return unless str.sub!(/\A( \d|\d{1,2})/, '') - val = $1.to_i - return unless (0..24) === val - e.hour = val - when 'I', 'l', 'OI' - return unless str.sub!(/\A( \d|\d{1,2})/, '') - val = $1.to_i - return unless (1..12) === val - e.hour = val - when 'j' - return unless str.sub!(/\A(\d{1,3})/, '') - val = $1.to_i - return unless (1..366) === val - e.yday = val - when 'L' - return unless str.sub!(if num_pattern?($') - then /\A([-+]?\d{1,3})/ - else /\A([-+]?\d{1,})/ - end, '') -# val = Rational($1.to_i, 10**3) - val = Rational($1.to_i, 10**$1.size) - e.sec_fraction = val - when 'M', 'OM' - return unless str.sub!(/\A(\d{1,2})/, '') - val = $1.to_i - return unless (0..59) === val - e.min = val - when 'm', 'Om' - return unless str.sub!(/\A(\d{1,2})/, '') - val = $1.to_i - return unless (1..12) === val - e.mon = val - when 'N' - return unless str.sub!(if num_pattern?($') - then /\A([-+]?\d{1,9})/ - else /\A([-+]?\d{1,})/ - end, '') -# val = Rational($1.to_i, 10**9) - val = Rational($1.to_i, 10**$1.size) - e.sec_fraction = val - when 'n', 't' - return unless _strptime_i(str, "\s", e) - when 'P', 'p' - return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '') - e._merid = if $1.downcase == 'a' then 0 else 12 end - when 'Q' - return unless str.sub!(/\A(-?\d{1,})/, '') - val = Rational($1.to_i, 10**3) - e.seconds = val - when 'R' - return unless _strptime_i(str, '%H:%M', e) - when 'r' - return unless _strptime_i(str, '%I:%M:%S %p', e) - when 'S', 'OS' - return unless str.sub!(/\A(\d{1,2})/, '') - val = $1.to_i - return unless (0..60) === val - e.sec = val - when 's' - return unless str.sub!(/\A(-?\d{1,})/, '') - val = $1.to_i - e.seconds = val - when 'T' - return unless _strptime_i(str, '%H:%M:%S', e) - when 'U', 'W', 'OU', 'OW' - return unless str.sub!(/\A(\d{1,2})/, '') - val = $1.to_i - return unless (0..53) === val - e.__send__(if s[-1,1] == 'U' then :wnum0= else :wnum1= end, val) - when 'u', 'Ou' - return unless str.sub!(/\A(\d{1})/, '') - val = $1.to_i - return unless (1..7) === val - e.cwday = val - when 'V', 'OV' - return unless str.sub!(/\A(\d{1,2})/, '') - val = $1.to_i - return unless (1..53) === val - e.cweek = val - when 'v' - return unless _strptime_i(str, '%e-%b-%Y', e) - when 'w' - return unless str.sub!(/\A(\d{1})/, '') - val = $1.to_i - return unless (0..6) === val - e.wday = val - when 'X', 'EX' - return unless _strptime_i(str, '%H:%M:%S', e) - when 'x', 'Ex' - return unless _strptime_i(str, '%m/%d/%y', e) - when 'Y', 'EY' - return unless str.sub!(if num_pattern?($') - then /\A([-+]?\d{1,4})/ - else /\A([-+]?\d{1,})/ - end, '') - val = $1.to_i - e.year = val - when 'y', 'Ey', 'Oy' - return unless str.sub!(/\A(\d{1,2})/, '') - val = $1.to_i - return unless (0..99) === val - e.year = val - e._cent ||= if val >= 69 then 19 else 20 end - when 'Z', /\A:{0,3}z/ - return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)? - |[[:alpha:].\s]+(?:standard|daylight)\s+time\b - |[[:alpha:]]+(?:\s+dst)?\b - )/ix, '') - val = $1 - e.zone = val - offset = zone_to_diff(val) - e.offset = offset - when '%' - return unless str.sub!(/\A%/, '') - when '+' - return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e) - else - return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '') - end - else - case c - when /\A\s/ - str.sub!(/\A\s+/, '') - else - return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '') - end - end - end - end - - private_class_method :_strptime_i - - def self._strptime(str, fmt='%F') - str = str.dup - e = Format::Bag.new - return unless _strptime_i(str, fmt, e) - - if e._cent - if e.cwyear - e.cwyear += e._cent * 100 - end - if e.year - e. year += e._cent * 100 - end - end - - if e._merid - if e.hour - e.hour %= 12 - e.hour += e._merid - end - end - - unless str.empty? - e.leftover = str - end - - e.to_hash - end - def self.s3e(e, y, m, d, bc=false) unless String === m m = m.to_s @@ -1073,10 +858,6 @@ end class DateTime < Date - def self._strptime(str, fmt='%FT%T%z') - super(str, fmt) - end - def iso8601_timediv(n) # :nodoc: strftime('T%T' + if n < 1 -- cgit v1.2.3