[前][次][番号順一覧][スレッド一覧]

ruby-changes:19284

From: tadf <ko1@a...>
Date: Sat, 23 Apr 2011 21:43:08 +0900 (JST)
Subject: [ruby-changes:19284] Ruby:r31322 (trunk): * ext/date/date_core.c: replacement of implementation of

tadf	2011-04-23 21:31:15 +0900 (Sat, 23 Apr 2011)

  New Revision: 31322

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=31322

  Log:
    * ext/date/date_core.c: replacement of implementation of
      _parse.  [experimental]
    * ext/date/date_parse.c: new.
    * ext/date/lib/date/format.rb: removed ruby version of _parse.

  Added files:
    trunk/ext/date/date_parse.c
  Modified files:
    trunk/ChangeLog
    trunk/ext/date/date_core.c
    trunk/ext/date/lib/date/format.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 31321)
+++ ChangeLog	(revision 31322)
@@ -1,3 +1,10 @@
+Sat Apr 23 21:29:42 2011  Tadayoshi Funaba  <tadf@d...>
+
+	* ext/date/date_core.c: replacement of implementation of
+	  _parse.  [experimental]
+	* ext/date/date_parse.c: new.
+	* ext/date/lib/date/format.rb: removed ruby version of _parse.
+
 Fri Apr 22 12:04:15 2011  NARUSE, Yui  <naruse@r...>
 
 	* array.c (rb_ary_sort_bang): fix rdoc.
Index: ext/date/date_core.c
===================================================================
--- ext/date/date_core.c	(revision 31321)
+++ ext/date/date_core.c	(revision 31322)
@@ -1417,7 +1417,7 @@
 
 /*
  * call-seq:
- *    Date._strptime(string, [format="%F"])
+ *    Date._strptime(string[, format="%F"])
  *
  * Return a hash of parsed elements.
  */
@@ -1427,8 +1427,52 @@
     return date_s__strptime_internal(argc, argv, klass, "%F");
 }
 
+VALUE
+date__parse(VALUE str, VALUE comp);
+
+static VALUE
+date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE vstr, vcomp, hash;
+    const char *str;
+
+    rb_scan_args(argc, argv, "11", &vstr, &vcomp);
+    StringValue(vstr);
+    if (!rb_enc_str_asciicompat_p(vstr))
+	rb_raise(rb_eArgError,
+		 "string should have ASCII compatible encoding");
+    str = RSTRING_PTR(vstr);
+    if (argc < 2)
+	vcomp = Qtrue;
+
+    hash = date__parse(vstr, vcomp);
+
+    {
+	VALUE zone = rb_hash_aref(hash, ID2SYM(rb_intern("zone")));
+
+	if (!NIL_P(zone)) {
+	    rb_enc_copy(zone, vstr);
+	    rb_hash_aset(hash, ID2SYM(rb_intern("zone")), zone);
+	}
+    }
+
+    return hash;
+}
+
 /*
  * call-seq:
+ *    Date._parse(string[, comp=true])
+ *
+ * Return a hash of parsed elements.
+ */
+static VALUE
+date_s__parse(int argc, VALUE *argv, VALUE klass)
+{
+    return date_s__parse_internal(argc, argv, klass);
+}
+
+/*
+ * call-seq:
  *    d.ajd
  *
  * Get the date as an Astronomical Julian Day Number.
@@ -3155,7 +3199,7 @@
 
 /*
  * call-seq:
- *    DateTime._strptime(string, [format="%FT%T%z"])
+ *    DateTime._strptime(string[, format="%FT%T%z"])
  *
  * Return a hash of parsed elements.
  */
@@ -4454,6 +4498,7 @@
     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_singleton_method(cDate, "_parse", date_s__parse, -1);
 
     rb_define_method(cDate, "ajd", d_lite_ajd, 0);
     rb_define_method(cDate, "amjd", d_lite_amjd, 0);
Index: ext/date/lib/date/format.rb
===================================================================
--- ext/date/lib/date/format.rb	(revision 31321)
+++ ext/date/lib/date/format.rb	(revision 31322)
@@ -1,4 +1,4 @@
-# format.rb: Written by Tadayoshi Funaba 1999-2010
+# format.rb: Written by Tadayoshi Funaba 1999-2011
 
 class Date
 
@@ -108,31 +108,8 @@
       x.freeze
     end
 
-    class BagStruct < Struct # :nodoc:
-
-      def to_hash
-	h = {}
-	members.each do |k|
-	  unless /\A_/ =~ k.to_s || self[k].nil?
-	    h[k] = self[k]
-	  end
-	end
-	h
-      end
-
-    end
-
-    Bag = BagStruct.new(:year, :mon, :yday, :mday, :wday,
-			:cwyear, :cweek, :cwday,
-			:hour, :min, :sec, :sec_fraction,
-			:wnum0, :wnum1, :seconds,
-			:zone, :offset, :leftover,
-			:_cent, :_merid, :_comp)
-
   end
 
-# alias_method :format, :strftime
-
   def asctime() strftime('%c') end
 
   alias_method :ctime, :asctime
@@ -167,512 +144,6 @@
     end
   end
 
-=begin
-  def beat(n=0)
-    i, f = (new_offset(HOURS_IN_DAY).day_fraction * 1000).divmod(1)
-    ('@%03d' % i) +
-      if n < 1
-	''
-      else
-	'.%0*d' % [n, (f / Rational(1, 10**n)).round]
-      end
-  end
-=end
-
-  def self.s3e(e, y, m, d, bc=false)
-    unless String === m
-      m = m.to_s
-    end
-
-    if y && m && !d
-      y, m, d = d, y, m
-    end
-
-    if y == nil
-      if d && d.size > 2
-	y = d
-	d = nil
-      end
-      if d && d[0,1] == "'"
-	y = d
-	d = nil
-      end
-    end
-
-    if y
-      y.scan(/(\d+)(.+)?/)
-      if $2
-	y, d = d, $1
-      end
-    end
-
-    if m
-      if m[0,1] == "'" || m.size > 2
-	y, m, d = m, d, y # us -> be
-      end
-    end
-
-    if d
-      if d[0,1] == "'" || d.size > 2
-	y, d = d, y
-      end
-    end
-
-    if y
-      y =~ /([-+])?(\d+)/
-      if $1 || $2.size > 2
-	c = false
-      end
-      iy = $&.to_i
-      if bc
-	iy = -iy + 1
-      end
-      e.year = iy
-    end
-
-    if m
-      m =~ /\d+/
-      e.mon = $&.to_i
-    end
-
-    if d
-      d =~ /\d+/
-      e.mday = $&.to_i
-    end
-
-    if c != nil
-      e._comp = c
-    end
-
-  end
-
-  private_class_method :s3e
-
-  def self._parse_day(str, e) # :nodoc:
-    if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/io, ' ')
-      e.wday = Format::ABBR_DAYS[$1.downcase]
-      true
-=begin
-    elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/i, ' ')
-      e.wday = %w(su mo tu we th fr sa).index($1.downcase)
-      true
-=end
-    end
-  end
-
-  def self._parse_time(str, e) # :nodoc:
-    if str.sub!(
-		/(
-		   (?:
-		     \d+\s*:\s*\d+
-		     (?:
-		       \s*:\s*\d+(?:[,.]\d*)?
-		     )?
-		   |
-		     \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
-		   )
-		   (?:
-		     \s*
-		     [ap](?:m\b|\.m\.)
-		   )?
-		 |
-		   \d+\s*[ap](?:m\b|\.m\.)
-		 )
-		 (?:
-		   \s*
-		   (
-		     (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
-		   |
-		     [[:alpha:].\s]+(?:standard|daylight)\stime\b
-		   |
-		     [[:alpha:]]+(?:\sdst)?\b
-		   )
-		 )?
-		/ix,
-		' ')
-
-      t = $1
-      e.zone = $2 if $2
-
-      t =~ /\A(\d+)h?
-	      (?:\s*:?\s*(\d+)m?
-		(?:
-		  \s*:?\s*(\d+)(?:[,.](\d+))?s?
-		)?
-	      )?
-	    (?:\s*([ap])(?:m\b|\.m\.))?/ix
-
-      e.hour = $1.to_i
-      e.min = $2.to_i if $2
-      e.sec = $3.to_i if $3
-      e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
-
-      if $5
-	e.hour %= 12
-	if $5.downcase == 'p'
-	  e.hour += 12
-	end
-      end
-      true
-    end
-  end
-
-=begin
-  def self._parse_beat(str, e) # :nodoc:
-    if str.sub!(/@\s*(\d+)(?:[,.](\d*))?/, ' ')
-      beat = Rational($1.to_i)
-      beat += Rational($2.to_i, 10**$2.size) if $2
-      secs = Rational(beat, 1000)
-      h, min, s, fr = self.day_fraction_to_time(secs)
-      e.hour = h
-      e.min = min
-      e.sec = s
-      e.sec_fraction = fr * 86400
-      e.zone = '+01:00'
-      true
-    end
-  end
-=end
-
-  def self._parse_eu(str, e) # :nodoc:
-    if str.sub!(
-		/'?(\d+)[^-\d\s]*
-		 \s*
-		 (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
-		 (?:
-		   \s*
-		   (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
-		   \s*
-		   ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
-		 )?
-		/iox,
-		' ') # '
-      s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
-	  $3 && $3[0,1].downcase == 'b')
-      true
-    end
-  end
-
-  def self._parse_us(str, e) # :nodoc:
-    if str.sub!(
-		/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
-		 \s*
-		 ('?\d+)[^-\d\s']*
-		 (?:
-		   \s*
-		   (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
-		   \s*
-		   ('?-?\d+)
-		 )?
-		/iox,
-		' ') # '
-      s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
-	  $3 && $3[0,1].downcase == 'b')
-      true
-    end
-  end
-
-  def self._parse_iso(str, e) # :nodoc:
-    if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/, ' ')
-      s3e(e, $1, $2, $3)
-      true
-    end
-  end
-
-  def self._parse_iso2(str, e) # :nodoc:
-    if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/i, ' ')
-      e.cwyear = $1.to_i if $1
-      e.cweek = $2.to_i
-      e.cwday = $3.to_i if $3
-      true
-    elsif str.sub!(/-w-(\d)\b/i, ' ')
-      e.cwday = $1.to_i
-      true
-    elsif str.sub!(/--(\d{2})?-(\d{2})\b/, ' ')
-      e.mon = $1.to_i if $1
-      e.mday = $2.to_i
-      true
-    elsif str.sub!(/--(\d{2})(\d{2})?\b/, ' ')
-      e.mon = $1.to_i
-      e.mday = $2.to_i if $2
-      true
-    elsif /[,.](\d{2}|\d{4})-\d{3}\b/ !~ str &&
-	str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/, ' ')
-      e.year = $1.to_i
-      e.yday = $2.to_i
-      true
-    elsif /\d-\d{3}\b/ !~ str &&
-	str.sub!(/\b-(\d{3})\b/, ' ')
-      e.yday = $1.to_i
-      true
-    end
-  end
-
-  def self._parse_jis(str, e) # :nodoc:
-    if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/i, ' ')
-      era = { 'm'=>1867,
-	      't'=>1911,
-	      's'=>1925,
-	      'h'=>1988
-	  }[$1.downcase]
-      e.year = $2.to_i + era
-      e.mon = $3.to_i
-      e.mday = $4.to_i
-      true
-    end
-  end
-
-  def self._parse_vms(str, e) # :nodoc:
-    if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
-		-('?-?\d+)/iox, ' ')
-      s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
-      true
-    elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
-		-('?-?\d+)(?:-('?-?\d+))?/iox, ' ')
-      s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
-      true
-    end
-  end
-
-  def self._parse_sla(str, e) # :nodoc:
-    if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|, ' ') # '
-      s3e(e, $1, $2, $3)
-      true
-    end
-  end
-
-  def self._parse_dot(str, e) # :nodoc:
-    if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|, ' ') # '
-      s3e(e, $1, $2, $3)
-      true
-    end
-  end
-
-  def self._parse_year(str, e) # :nodoc:
-    if str.sub!(/'(\d+)\b/, ' ')
-      e.year = $1.to_i
-      true
-    end
-  end
-
-  def self._parse_mon(str, e) # :nodoc:
-    if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/io, ' ')
-      e.mon = Format::ABBR_MONTHS[$1.downcase]
-      true
-    end
-  end
-
-  def self._parse_mday(str, e) # :nodoc:
-    if str.sub!(/(\d+)(st|nd|rd|th)\b/i, ' ')
-      e.mday = $1.to_i
-      true
-    end
-  end
-
-  def self._parse_ddd(str, e) # :nodoc:
-    if str.sub!(
-		/([-+]?)(\d{2,14})
-		  (?:
-		    \s*
-		    t?
-		    \s*
-		    (\d{2,6})?(?:[,.](\d*))?
-		  )?
-		  (?:
-		    \s*
-		    (
-		      z\b
-		    |
-		      [-+]\d{1,4}\b
-		    |
-		      \[[-+]?\d[^\]]*\]
-		    )
-		  )?
-		/ix,
-		' ')
-      case $2.size
-      when 2
-	if $3.nil? && $4
-	  e.sec  = $2[-2, 2].to_i
-	else
-	  e.mday = $2[ 0, 2].to_i
-	end
-      when 4
-	if $3.nil? && $4
-	  e.sec  = $2[-2, 2].to_i
-	  e.min  = $2[-4, 2].to_i
-	else
-	  e.mon  = $2[ 0, 2].to_i
-	  e.mday = $2[ 2, 2].to_i
-	end
-      when 6
-	if $3.nil? && $4
-	  e.sec  = $2[-2, 2].to_i
-	  e.min  = $2[-4, 2].to_i
-	  e.hour = $2[-6, 2].to_i
-	else
-	  e.year = ($1 + $2[ 0, 2]).to_i
-	  e.mon  = $2[ 2, 2].to_i
-	  e.mday = $2[ 4, 2].to_i
-	end
-      when 8, 10, 12, 14
-	if $3.nil? && $4
-	  e.sec  = $2[-2, 2].to_i
-	  e.min  = $2[-4, 2].to_i
-	  e.hour = $2[-6, 2].to_i
-	  e.mday = $2[-8, 2].to_i
-	  if $2.size >= 10
-	    e.mon  = $2[-10, 2].to_i
-	  end
-	  if $2.size == 12
-	    e.year = ($1 + $2[-12, 2]).to_i
-	  end
-	  if $2.size == 14
-	    e.year = ($1 + $2[-14, 4]).to_i
-	    e._comp = false
-	  end
-	else
-	  e.year = ($1 + $2[ 0, 4]).to_i
-	  e.mon  = $2[ 4, 2].to_i
-	  e.mday = $2[ 6, 2].to_i
-	  e.hour = $2[ 8, 2].to_i if $2.size >= 10
-	  e.min  = $2[10, 2].to_i if $2.size >= 12
-	  e.sec  = $2[12, 2].to_i if $2.size >= 14
-	  e._comp = false
-	end
-      when 3
-	if $3.nil? && $4
-	  e.sec  = $2[-2, 2].to_i
-	  e.min  = $2[-3, 1].to_i
-	else
-	  e.yday = $2[ 0, 3].to_i
-	end
-      when 5
-	if $3.nil? && $4
-	  e.sec  = $2[-2, 2].to_i
-	  e.min  = $2[-4, 2].to_i
-	  e.hour = $2[-5, 1].to_i
-	else
-	  e.year = ($1 + $2[ 0, 2]).to_i
-	  e.yday = $2[ 2, 3].to_i
-	end
-      when 7
-	if $3.nil? && $4
-	  e.sec  = $2[-2, 2].to_i
-	  e.min  = $2[-4, 2].to_i
-	  e.hour = $2[-6, 2].to_i
-	  e.mday = $2[-7, 1].to_i
-	else
-	  e.year = ($1 + $2[ 0, 4]).to_i
-	  e.yday = $2[ 4, 3].to_i
-	end
-      end
-      if $3
-	if $4
-	  case $3.size
-	  when 2, 4, 6
-	    e.sec  = $3[-2, 2].to_i
-	    e.min  = $3[-4, 2].to_i if $3.size >= 4
-	    e.hour = $3[-6, 2].to_i if $3.size >= 6
-	  end
-	else
-	  case $3.size
-	  when 2, 4, 6
-	    e.hour = $3[ 0, 2].to_i
-	    e.min  = $3[ 2, 2].to_i if $3.size >= 4
-	    e.sec  = $3[ 4, 2].to_i if $3.size >= 6
-	  end
-	end
-      end
-      if $4
-	e.sec_fraction = Rational($4.to_i, 10**$4.size)
-      end
-      if $5
-	e.zone = $5
-	if e.zone[0,1] == '['
-	  o, n, = e.zone[1..-2].split(':')
-	  e.zone = n || o
-	  if /\A\d/ =~ o
-	    o = format('+%s', o)
-	  end
-	  e.offset = zone_to_diff(o)
-	end
-      end
-      true
-    end
-  end
-
-  private_class_method :_parse_day, :_parse_time, # :_parse_beat,
-	:_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
-	:_parse_jis, :_parse_vms, :_parse_sla, :_parse_dot,
-	:_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
-
-  def self._parse(str, comp=true)
-    str = str.dup
-
-    e = Format::Bag.new
-
-    e._comp = comp
-
-    str.gsub!(/[^-+',.\/:@[:alnum:]\[\]]+/, ' ')
-
-    _parse_time(str, e) # || _parse_beat(str, e)
-    _parse_day(str, e)
-
-    _parse_eu(str, e)     ||
-    _parse_us(str, e)     ||
-    _parse_iso(str, e)    ||
-    _parse_jis(str, e)    ||
-    _parse_vms(str, e)    ||
-    _parse_sla(str, e)    ||
-    _parse_dot(str, e)    ||
-    _parse_iso2(str, e)   ||
-    _parse_year(str, e)   ||
-    _parse_mon(str, e)    ||
-    _parse_mday(str, e)   ||
-    _parse_ddd(str, e)
-
-    if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/i, ' ')
-      if e.year
-	e.year = -e.year + 1
-      end
-    end
-
-    if str.sub!(/\A\s*(\d{1,2})\s*\z/, ' ')
-      if e.hour && !e.mday
-	v = $1.to_i
-	if (1..31) === v
-	  e.mday = v
-	end
-      end
-      if e.mday && !e.hour
-	v = $1.to_i
-	if (0..24) === v
-	  e.hour = v
-	end
-      end
-    end
-
-    if e._comp
-      if e.cwyear
-	if e.cwyear >= 0 && e.cwyear <= 99
-	  e.cwyear += if e.cwyear >= 69
-		      then 1900 else 2000 end
-	end
-      end
-      if e.year
-	if e.year >= 0 && e.year <= 99
-	  e.year += if e.year >= 69
-		    then 1900 else 2000 end
-	end
-      end
-    end
-
-    e.offset ||= zone_to_diff(e.zone) if e.zone
-
-    e.to_hash
-  end
-
   def self._iso8601(str) # :nodoc:
     if /\A\s*(([-+]?\d{2,}|-)-\d{2}-\d{2}|
 	      ([-+]?\d{2,})?-\d{3}|
@@ -712,42 +183,42 @@
 	(?:t
 	  (\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?
 	(z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
-      e = Format::Bag.new
-      e.year = $1.to_i
-      e.mon = $2.to_i if $2
-      e.mday = $3.to_i if $3
-      e.hour = $4.to_i if $4
-      e.min = $5.to_i if $5
-      e.sec = $6.to_i if $6
-      e.sec_fraction = Rational($7.to_i, 10**$7.size) if $7
+      e = {}
+      e[:year] = $1.to_i
+      e[:mon] = $2.to_i if $2
+      e[:mday] = $3.to_i if $3
+      e[:hour] = $4.to_i if $4
+      e[:min] = $5.to_i if $5
+      e[:sec] = $6.to_i if $6
+      e[:sec_fraction] = Rational($7.to_i, 10**$7.size) if $7
       if $8
-	e.zone = $8
-	e.offset = zone_to_diff($8)
+	e[:zone] = $8
+	e[:offset] = zone_to_diff($8)
       end
-      e.to_hash
+      e
     elsif /\A\s*(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?
 	(z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
-      e = Format::Bag.new
-      e.hour = $1.to_i if $1
-      e.min = $2.to_i if $2
-      e.sec = $3.to_i if $3
-      e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
+      e = {}
+      e[:hour] = $1.to_i if $1
+      e[:min] = $2.to_i if $2
+      e[:sec] = $3.to_i if $3
+      e[:sec_fraction] = Rational($4.to_i, 10**$4.size) if $4
       if $5
-	e.zone = $5
-	e.offset = zone_to_diff($5)
+	e[:zone] = $5
+	e[:offset] = zone_to_diff($5)
       end
-      e.to_hash
+      e
     elsif /\A\s*(?:--(\d{2})(?:-(\d{2}))?|---(\d{2}))
 	(z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
-      e = Format::Bag.new
-      e.mon = $1.to_i if $1
-      e.mday = $2.to_i if $2
-      e.mday = $3.to_i if $3
+      e = {}
+      e[:mon] = $1.to_i if $1
+      e[:mday] = $2.to_i if $2
+      e[:mday] = $3.to_i if $3
       if $4
-	e.zone = $4
-	e.offset = zone_to_diff($4)
+	e[:zone] = $4
+	e[:offset] = zone_to_diff($4)
       end
-      e.to_hash
+      e
     end
   end
 
@@ -756,7 +227,7 @@
 	\d{1,2}\s+
 	(?:#{Format::ABBR_MONTHS.keys.join('|')})\s+
 	-?(\d{2,})\s+ # allow minus, anyway
-	\d{2}:\d{2}(:\d{2})?\s*
+	\d{2}:\d{2}(?::\d{2})?\s*
 	(?:[-+]\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\s*\z/iox =~ str
       e = _parse(str, false)
       if $1.size < 4
@@ -811,48 +282,41 @@
     end
   end
 
-  t = Module.new do
-
-    private
-
-    def zone_to_diff(zone) # :nodoc:
-      zone = zone.downcase
-      if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
-	dst = $1 == 'daylight'
+  def self.zone_to_diff(zone) # :nodoc:
+    zone = zone.downcase
+    if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
+      dst = $1 == 'daylight'
+    else
+      dst = zone.sub!(/\s+dst\z/, '')
+    end
+    if Format::ZONES.include?(zone)
+      offset = Format::ZONES[zone]
+      offset += 3600 if dst
+    elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
+      sign = $1
+      if zone.include?(':')
+	hour, min, sec, = zone.split(':')
+      elsif zone.include?(',') || zone.include?('.')
+	hour, fr, = zone.split(/[,.]/)
+	min = Rational(fr.to_i, 10**fr.size) * 60
       else
-	dst = zone.sub!(/\s+dst\z/, '')
-      end
-      if Format::ZONES.include?(zone)
-	offset = Format::ZONES[zone]
-	offset += 3600 if dst
-      elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
-	sign = $1
-	if zone.include?(':')
-	  hour, min, sec, = zone.split(':')
-	elsif zone.include?(',') || zone.include?('.')
-	  hour, fr, = zone.split(/[,.]/)
-	  min = Rational(fr.to_i, 10**fr.size) * 60
+	if (zone.size % 2) == 1
+	  hour = zone[0,1]
+	  min = zone[1,2]
+	  sec = zone[3,2]
 	else
-	  case zone.size
-	  when 3
-	    hour = zone[0,1]
-	    min = zone[1,2]
-	  else
-	    hour = zone[0,2]
-	    min = zone[2,2]
-	    sec = zone[4,2]
-	  end
+	  hour = zone[0,2]
+	  min = zone[2,2]
+	  sec = zone[4,2]
 	end
-	offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
-	offset *= -1 if sign == '-'
       end
-      offset
+      offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
+      offset *= -1 if sign == '-'
     end
-
+    offset
   end
 
-  extend  t
-  include t
+  private_class_method :zone_to_diff
 
 end
 
Index: ext/date/date_parse.c
===================================================================
--- ext/date/date_parse.c	(revision 0)
+++ ext/date/date_parse.c	(revision 31322)
@@ -0,0 +1,1349 @@
+/*
+  date_parse.c: Coded by Tadayoshi Funaba 2011
+*/
+
+#include "ruby.h"
+#include "ruby/encoding.h"
+#include "ruby/re.h"
+#include <ctype.h>
+
+#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_to_s(x) rb_funcall(x, rb_intern("to_s"), 0)
+
+#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_aref2(o,i,j) rb_funcall(o, rb_intern("[]"), 2, i, j)
+#define f_begin(o,i) rb_funcall(o, rb_intern("begin"), 1, i)
+#define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i)
+#define f_aset(o,i,v) rb_funcall(o, rb_intern("[]="), 2, i, v)
+#define f_aset2(o,i,j,v) rb_funcall(o, rb_intern("[]="), 3, i, j, v)
+#define f_sub_bang(s,r,x) rb_funcall(s, rb_intern("sub!"), 2, r, x)
+#define f_gsub_bang(s,r,x) rb_funcall(s, rb_intern("gsub!"), 2, r, x)
+#define f_split(s,p) rb_funcall(s, rb_intern("split"), 1, p)
+#define f_downcase(x) rb_funcall(x, rb_intern("downcase"), 0)
+
+#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 cstr2num(s) rb_cstr_to_inum(s, 10, 0)
+#define str2num(s) rb_str_to_inum(s, 10, 0)
+
+static const char *abbr_days[] = {
+    "sun", "mon", "tue", "wed",
+    "thu", "fri", "sat"
+};
+
+static const char *abbr_months[] = {
+    "jan", "feb", "mar", "apr", "may", "jun",
+    "jul", "aug", "sep", "oct", "nov", "dec"
+};
+
+static void
+s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc)
+{
+    VALUE c = Qnil;
+
+    if (TYPE(m) != T_STRING)
+	m = f_to_s(m);
+
+    if (!NIL_P(y) && !NIL_P(m) && NIL_P(d)) {
+	VALUE oy = y;
+	VALUE om = m;
+	VALUE od = d;
+
+	y = od;
+	m = oy;
+	d = om;
+    }
+
+    if (NIL_P(y)) {
+	if (!NIL_P(d) && RSTRING_LEN(d) > 2) {
+	    y = d;
+	    d = Qnil;
+	}
+	if (!NIL_P(d) && *RSTRING_PTR(d) == '\'') {
+		y = d;
+		d = Qnil;
+	}
+    }
+
+    if (!NIL_P(y)) {
+	const char *s, *bp, *ep;
+	size_t l;
+
+	s = RSTRING_PTR(y);
+	while (*s != '-' && *s != '+' && !isdigit(*s))
+	    s++;
+	bp = s;
+	if (*s == '-' || *s == '+') {
+	    s++;
+	}
+	l = strspn(s, "0123456789");
+	ep = s + l;
+	if (*ep) {
+	    y = d;
+	    d = rb_str_new(bp, ep - bp);
+	}
+    }
+
+    if (!NIL_P(m)) {
+	const char *s;
+
+	s = RSTRING_PTR(m);
+	if (*s == '\'' || RSTRING_LEN(m) > 2) {
+	    /* us -> be */
+	    VALUE oy = y;
+	    VALUE om = m;
+	    VALUE od = d;
+
+	    y = om;
+	    m = od;
+	    d = oy;
+	}
+    }
+
+    if (!NIL_P(d)) {
+	const char *s;
+
+	s = RSTRING_PTR(d);
+	if (*s == '\'' || RSTRING_LEN(d) > 2) {
+	    VALUE oy = y;
+	    VALUE od = d;
+
+	    y = od;
+	    d = oy;
+	}
+    }
+
+    if (!NIL_P(y)) {
+	const char *s, *bp, *ep;
+	int sign = 0;
+	size_t l;
+	VALUE iy;
+
+	s = RSTRING_PTR(y);
+	while (*s != '-' && *s != '+' && !isdigit(*s))
+	    s++;
+	bp = s;
+	if (*s == '-' || *s == '+') {
+	    s++;
+	    sign = 1;
+	}
+	if (sign)
+	    c = Qfalse;
+	l = strspn(s, "0123456789");
+	ep = s + l;
+	if (l > 2)
+	    c = Qfalse;
+	{
+	    char *buf;
+
+	    buf = ALLOC_N(char, ep - bp + 1);
+	    memcpy(buf, bp, ep - bp);
+	    buf[ep - bp] = '\0';
+	    iy = cstr2num(buf);
+	}
+	if (bc)
+	    iy = f_add(f_negate(iy), INT2FIX(1));
+	set_hash("year", iy);
+    }
+
+    if (!NIL_P(m)) {
+	const char *s, *bp, *ep;
+	size_t l;
+	VALUE im;
+
+	s = RSTRING_PTR(m);
+	while (!isdigit(*s))
+	    s++;
+	bp = s;
+	l = strspn(s, "0123456789");
+	ep = s + l;
+	{
+	    char *buf;
+
+	    buf = ALLOC_N(char, ep - bp + 1);
+	    memcpy(buf, bp, ep - bp);
+	    buf[ep - bp] = '\0';
+	    im = cstr2num(buf);
+	}
+	set_hash("mon", im);
+    }
+
+    if (!NIL_P(d)) {
+	const char *s, *bp, *ep;
+	size_t l;
+	VALUE id;
+
+	s = RSTRING_PTR(d);
+	while (!isdigit(*s))
+	    s++;
+	bp = s;
+	l = strspn(s, "0123456789");
+	ep = s + l;
+	{
+	    char *buf;
+
+	    buf = ALLOC_N(char, ep - bp + 1);
+	    memcpy(buf, bp, ep - bp);
+	    buf[ep - bp] = '\0';
+	    id = cstr2num(buf);
+	}
+	set_hash("mday", id);
+    }
+
+    if (!NIL_P(c))
+	set_hash("_comp", c);
+}
+
+#define ABBR_DAYS "sun|mon|tue|wed|thu|fri|sat"
+#define ABBR_MONTHS "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"
+
+static VALUE
+regcomp(const char *source, long len, int opt)
+{
+    VALUE pat;
+
+    pat = rb_reg_new(source, len, opt);
+    rb_gc_register_mark_object(pat);
+    return pat;
+}
+
+#define REGCOMP(pat,opt) \
+{ \
+    if (NIL_P(pat)) \
+	pat = regcomp(pat##_source, sizeof pat##_source - 1, opt); \
+}
+
+#define REGCOMP_0(pat) REGCOMP(pat, 0)
+#define REGCOMP_I(pat) REGCOMP(pat, ONIG_OPTION_IGNORECASE)
+
+#define SUBS(s,p,c) \
+{ \
+    return subs(s, p, hash, c);	\
+}
+
+static int
+subs(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
+{
+    VALUE m;
+
+    m = f_match(pat, str);
+
+    if (NIL_P(m))
+	return 0;
+
+    {
+	VALUE be, en;
+
+	be = f_begin(m, INT2FIX(0));
+	en = f_end(m, INT2FIX(0));
+	f_aset2(str, be, LONG2NUM(NUM2LONG(en) - NUM2LONG(be)),
+		rb_str_new(" ", 1));
+	(*cb)(m, hash);
+    }
+
+    return 1;
+}
+
+static int
+day_num(VALUE s)
+{
+    int i;
+
+    for (i = 0; i < (int)sizeof_array(abbr_days); i++)
+	if (strncasecmp(abbr_days[i], RSTRING_PTR(s), 3) == 0)
+	    break;
+    return i;
+}
+
+static int
+mon_num(VALUE s)
+{
+    int i;
+
+    for (i = 0; i < (int)sizeof_array(abbr_months); i++)
+	if (strncasecmp(abbr_months[i], RSTRING_PTR(s), 3) == 0)
+	    break;
+    return i + 1;
+}
+
+static int
+parse_day_cb(VALUE m, VALUE hash)
+{
+    VALUE s;
+
+    s = f_aref(m, INT2FIX(1));
+    set_hash("wday", INT2FIX(day_num(s)));
+    return 1;
+}
+
+static int
+parse_day(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"\\b(" ABBR_DAYS ")[^-\\d\\s]*";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_day_cb);
+}
+
+static int
+parse_time2_cb(VALUE m, VALUE hash)
+{
+    VALUE h, min, s, f, p;
+
+    h = f_aref(m, INT2FIX(1));
+    h = str2num(h);
+
+    min = f_aref(m, INT2FIX(2));
+    if (!NIL_P(min))
+	min = str2num(min);
+
+    s = f_aref(m, INT2FIX(3));
+    if (!NIL_P(s))
+	s = str2num(s);
+
+    f = f_aref(m, INT2FIX(4));
+
+    if (!NIL_P(f))
+	f = rb_rational_new2(str2num(f),
+			     f_expt(INT2FIX(10), LONG2NUM(RSTRING_LEN(f))));
+
+    p = f_aref(m, INT2FIX(5));
+
+    if (!NIL_P(p)) {
+	int ih = NUM2INT(h);
+	ih %= 12;
+	if (*RSTRING_PTR(p) == 'P' || *RSTRING_PTR(p) == 'p')
+	    ih += 12;
+	h = INT2FIX(ih);
+    }
+
+    set_hash("hour", h);
+    if (!NIL_P(min))
+	set_hash("min", min);
+    if (!NIL_P(s))
+	set_hash("sec", s);
+    if (!NIL_P(f))
+	set_hash("sec_fraction", f);
+
+    return 1;
+}
+
+static int
+parse_time_cb(VALUE m, VALUE hash)
+{
+    static const char pat_source[] =
+            "\\A(\\d+)h?"
+	      "(?:\\s*:?\\s*(\\d+)m?"
+		"(?:"
+		  "\\s*:?\\s*(\\d+)(?:[,.](\\d+))?s?"
+		")?"
+	      ")?"
+	    "(?:\\s*([ap])(?:m\\b|\\.m\\.))?";
+    static VALUE pat = Qnil;
+    VALUE s1, s2;
+
+    s1 = f_aref(m, INT2FIX(1));
+    s2 = f_aref(m, INT2FIX(2));
+
+    if (!NIL_P(s2))
+	set_hash("zone", s2);
+
+    REGCOMP_I(pat);
+
+    {
+	VALUE m = f_match(pat, s1);
+
+	if (NIL_P(m))
+	    return 0;
+	parse_time2_cb(m, hash);
+    }
+
+    return 1;
+}
+
+static int
+parse_time(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+		"("
+		   "(?:"
+		     "\\d+\\s*:\\s*\\d+"
+		     "(?:"
+		       "\\s*:\\s*\\d+(?:[,.]\\d*)?"
+		     ")?"
+		   "|"
+		     "\\d+\\s*h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?"
+		   ")"
+		   "(?:"
+		     "\\s*"
+		     "[ap](?:m\\b|\\.m\\.)"
+		   ")?"
+		 "|"
+		   "\\d+\\s*[ap](?:m\\b|\\.m\\.)"
+		 ")"
+		 "(?:"
+		   "\\s*"
+		   "("
+		     "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?"
+		   "|"
+		     "[[:alpha:].\\s]+(?:standard|daylight)\\stime\\b"
+		   "|"
+		     "[[:alpha:]]+(?:\\sdst)?\\b"
+		   ")"
+		")?";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_time_cb);
+}
+
+static int
+parse_eu_cb(VALUE m, VALUE hash)
+{
+    VALUE y, mon, d, b;
+
+    d = f_aref(m, INT2FIX(1));
+    mon = f_aref(m, INT2FIX(2));
+    b = f_aref(m, INT2FIX(3));
+    y = f_aref(m, INT2FIX(4));
+
+    mon = INT2FIX(mon_num(mon));
+
+    s3e(hash, y, mon, d, !NIL_P(b) &&
+	(*RSTRING_PTR(b) == 'B' ||
+	 *RSTRING_PTR(b) == 'b'));
+    return 1;
+}
+
+static int
+parse_eu(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+		"'?(\\d+)[^-\\d\\s]*"
+		 "\\s*"
+		 "(" ABBR_MONTHS ")[^-\\d\\s']*"
+		 "(?:"
+		   "\\s*"
+		   "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
+		   "\\s*"
+		   "('?-?\\d+(?:(?:st|nd|rd|th)\\b)?)"
+		")?";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_eu_cb);
+}
+
+static int
+parse_us_cb(VALUE m, VALUE hash)
+{
+    VALUE y, mon, d, b;
+
+    mon = f_aref(m, INT2FIX(1));
+    d = f_aref(m, INT2FIX(2));
+    b = f_aref(m, INT2FIX(3));
+    y = f_aref(m, INT2FIX(4));
+
+    mon = INT2FIX(mon_num(mon));
+
+    s3e(hash, y, mon, d, !NIL_P(b) &&
+	(*RSTRING_PTR(b) == 'B' ||
+	 *RSTRING_PTR(b) == 'b'));
+    return 1;
+}
+
+static int
+parse_us(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+		"\\b(" ABBR_MONTHS ")[^-\\d\\s']*"
+		 "\\s*"
+		 "('?\\d+)[^-\\d\\s']*"
+		 "(?:"
+		   "\\s*"
+		   "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
+		   "\\s*"
+		   "('?-?\\d+)"
+		")?";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_us_cb);
+}
+
+static int
+parse_iso_cb(VALUE m, VALUE hash)
+{
+    VALUE y, mon, d;
+
+    y = f_aref(m, INT2FIX(1));
+    mon = f_aref(m, INT2FIX(2));
+    d = f_aref(m, INT2FIX(3));
+
+    s3e(hash, y, mon, d, 0);
+    return 1;
+}
+
+static int
+parse_iso(VALUE str, VALUE hash)
+{
+    static const char pat_source[] = "('?[-+]?\\d+)-(\\d+)-('?-?\\d+)";
+    static VALUE pat = Qnil;
+
+    REGCOMP_0(pat);
+    SUBS(str, pat, parse_iso_cb);
+}
+
+static int
+parse_iso21_cb(VALUE m, VALUE hash)
+{
+    VALUE y, w, d;
+
+    y = f_aref(m, INT2FIX(1));
+    w = f_aref(m, INT2FIX(2));
+    d = f_aref(m, INT2FIX(3));
+
+    if (!NIL_P(y))
+	set_hash("cwyear", str2num(y));
+    set_hash("cweek", str2num(w));
+    if (!NIL_P(d))
+	set_hash("cwday", str2num(d));
+
+    return 1;
+}
+
+static int
+parse_iso21(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"\\b(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_iso21_cb);
+}
+
+static int
+parse_iso22_cb(VALUE m, VALUE hash)
+{
+    VALUE d;
+
+    d = f_aref(m, INT2FIX(1));
+    set_hash("cwday", str2num(d));
+    return 1;
+}
+
+static int
+parse_iso22(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"-w-(\\d)\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_iso22_cb);
+}
+
+static int
+parse_iso23_cb(VALUE m, VALUE hash)
+{
+    VALUE mon, d;
+
+    mon = f_aref(m, INT2FIX(1));
+    d = f_aref(m, INT2FIX(2));
+
+    if (!NIL_P(mon))
+	set_hash("mon", str2num(mon));
+    set_hash("mday", str2num(d));
+
+    return 1;
+}
+
+static int
+parse_iso23(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"--(\\d{2})?-(\\d{2})\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_0(pat);
+    SUBS(str, pat, parse_iso23_cb);
+}
+
+static int
+parse_iso24_cb(VALUE m, VALUE hash)
+{
+    VALUE mon, d;
+
+    mon = f_aref(m, INT2FIX(1));
+    d = f_aref(m, INT2FIX(2));
+
+    set_hash("mon", str2num(mon));
+    if (!NIL_P(d))
+	set_hash("mday", str2num(d));
+
+    return 1;
+}
+
+static int
+parse_iso24(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"--(\\d{2})(\\d{2})?\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_0(pat);
+    SUBS(str, pat, parse_iso24_cb);
+}
+
+static int
+parse_iso25_cb(VALUE m, VALUE hash)
+{
+    VALUE y, d;
+
+    y = f_aref(m, INT2FIX(1));
+    d = f_aref(m, INT2FIX(2));
+
+    set_hash("year", str2num(y));
+    set_hash("yday", str2num(d));
+
+    return 1;
+}
+
+static int
+parse_iso25(VALUE str, VALUE hash)
+{
+    static const char pat0_source[] =
+	"[,.](\\d{2}|\\d{4})-\\d{3}\\b";
+    static VALUE pat0 = Qnil;
+    static const char pat_source[] =
+	"\\b(\\d{2}|\\d{4})-(\\d{3})\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_0(pat0);
+    REGCOMP_0(pat);
+
+    if (!NIL_P(f_match(pat0, str)))
+	return 0;
+    SUBS(str, pat, parse_iso25_cb);
+}
+
+static int
+parse_iso26_cb(VALUE m, VALUE hash)
+{
+    VALUE d;
+
+    d = f_aref(m, INT2FIX(1));
+    set_hash("yday", str2num(d));
+
+    return 1;
+}
+static int
+parse_iso26(VALUE str, VALUE hash)
+{
+    static const char pat0_source[] =
+	"\\d-\\d{3}\\b";
+    static VALUE pat0 = Qnil;
+    static const char pat_source[] =
+	"\\b-(\\d{3})\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_0(pat0);
+    REGCOMP_0(pat);
+
+    if (!NIL_P(f_match(pat0, str)))
+	return 0;
+    SUBS(str, pat, parse_iso26_cb);
+}
+
+static int
+parse_iso2(VALUE str, VALUE hash)
+{
+    if (parse_iso21(str, hash))
+	goto ok;
+    if (parse_iso22(str, hash))
+	goto ok;
+    if (parse_iso23(str, hash))
+	goto ok;
+    if (parse_iso24(str, hash))
+	goto ok;
+    if (parse_iso25(str, hash))
+	goto ok;
+    if (parse_iso26(str, hash))
+	goto ok;
+    return 0;
+
+  ok:
+    return 1;
+}
+
+static int
+parse_jis_cb(VALUE m, VALUE hash)
+{
+    VALUE e, y, mon, d;
+    int ep;
+
+    e = f_aref(m, INT2FIX(1));
+    y = f_aref(m, INT2FIX(2));
+    mon = f_aref(m, INT2FIX(3));
+    d = f_aref(m, INT2FIX(4));
+
+    switch (*RSTRING_PTR(e)) {
+      case 'M': case 'm': ep = 1867; break;
+      case 'T': case 't': ep = 1911; break;
+      case 'S': case 's': ep = 1925; break;
+      case 'H': case 'h': ep = 1988; break;
+      default:  ep = 0; break;
+    }
+
+    set_hash("year", f_add(str2num(y), INT2FIX(ep)));
+    set_hash("mon", str2num(mon));
+    set_hash("mday", str2num(d));
+
+    return 1;
+}
+
+static int
+parse_jis(VALUE str, VALUE hash)
+{
+    static const char pat_source[] = "\\b([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_jis_cb);
+}
+
+static int
+parse_vms11_cb(VALUE m, VALUE hash)
+{
+    VALUE y, mon, d;
+
+    d = f_aref(m, INT2FIX(1));
+    mon = f_aref(m, INT2FIX(2));
+    y = f_aref(m, INT2FIX(3));
+
+    mon = INT2FIX(mon_num(mon));
+
+    s3e(hash, y, mon, d, 0);
+    return 1;
+}
+
+static int
+parse_vms11(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"('?-?\\d+)-(" ABBR_MONTHS ")[^-]*"
+	"-('?-?\\d+)";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_vms11_cb);
+}
+
+static int
+parse_vms12_cb(VALUE m, VALUE hash)
+{
+    VALUE y, mon, d;
+
+    mon = f_aref(m, INT2FIX(1));
+    d = f_aref(m, INT2FIX(2));
+    y = f_aref(m, INT2FIX(3));
+
+    mon = INT2FIX(mon_num(mon));
+
+    s3e(hash, y, mon, d, 0);
+    return 1;
+}
+
+static int
+parse_vms12(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"\\b(" ABBR_MONTHS ")[^-]*"
+	"-('?-?\\d+)(?:-('?-?\\d+))?";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_vms12_cb);
+}
+
+static int
+parse_vms(VALUE str, VALUE hash)
+{
+    if (parse_vms11(str, hash))
+	goto ok;
+    if (parse_vms12(str, hash))
+	goto ok;
+    return 0;
+
+  ok:
+    return 1;
+}
+
+static int
+parse_sla_cb(VALUE m, VALUE hash)
+{
+    VALUE y, mon, d;
+
+    y = f_aref(m, INT2FIX(1));
+    mon = f_aref(m, INT2FIX(2));
+    d = f_aref(m, INT2FIX(3));
+
+    s3e(hash, y, mon, d, 0);
+    return 1;
+}
+
+static int
+parse_sla(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"('?-?\\d+)/\\s*('?\\d+)(?:\\D\\s*('?-?\\d+))?";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_sla_cb);
+}
+
+static int
+parse_dot_cb(VALUE m, VALUE hash)
+{
+    VALUE y, mon, d;
+
+    y = f_aref(m, INT2FIX(1));
+    mon = f_aref(m, INT2FIX(2));
+    d = f_aref(m, INT2FIX(3));
+
+    s3e(hash, y, mon, d, 0);
+    return 1;
+}
+
+static int
+parse_dot(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"('?-?\\d+)\\.\\s*('?\\d+)\\.\\s*('?-?\\d+)";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_dot_cb);
+}
+
+static int
+parse_year_cb(VALUE m, VALUE hash)
+{
+    VALUE y;
+
+    y = f_aref(m, INT2FIX(1));
+    set_hash("year", str2num(y));
+    return 1;
+}
+
+static int
+parse_year(VALUE str, VALUE hash)
+{
+    static const char pat_source[] = "'(\\d+)\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_0(pat);
+    SUBS(str, pat, parse_year_cb);
+}
+
+static int
+parse_mon_cb(VALUE m, VALUE hash)
+{
+    VALUE mon;
+
+    mon = f_aref(m, INT2FIX(1));
+    set_hash("mon", INT2FIX(mon_num(mon)));
+    return 1;
+}
+
+static int
+parse_mon(VALUE str, VALUE hash)
+{
+    static const char pat_source[] = "\\b(" ABBR_MONTHS ")\\S*";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_mon_cb);
+}
+
+static int
+parse_mday_cb(VALUE m, VALUE hash)
+{
+    VALUE d;
+
+    d = f_aref(m, INT2FIX(1));
+    set_hash("mday", str2num(d));
+    return 1;
+}
+
+static int
+parse_mday(VALUE str, VALUE hash)
+{
+    static const char pat_source[] = "(\\d+)(st|nd|rd|th)\\b";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_mday_cb);
+}
+
+static int
+n2i(const char *s, int f, int w)
+{
+    int e, v, i;
+    
+    e = f + w;
+    v = 0;
+    for (i = f; i < e; i++) {
+	v *= 10;
+	v += s[i] - '0';
+    }
+    return v;
+}
+
+static int
+parse_ddd_cb(VALUE m, VALUE hash)
+{
+    VALUE s1, s2, s3, s4, s5;
+    const char *cs2, *cs3, *cs5;
+    long l2, l3, l4, l5;
+
+    s1 = f_aref(m, INT2FIX(1));
+    s2 = f_aref(m, INT2FIX(2));
+    s3 = f_aref(m, INT2FIX(3));
+    s4 = f_aref(m, INT2FIX(4));
+    s5 = f_aref(m, INT2FIX(5));
+
+    cs2 = RSTRING_PTR(s2);
+    l2 = RSTRING_LEN(s2);
+
+    switch (l2) {
+      case 2:
+	if (NIL_P(s3) && !NIL_P(s4))
+	    set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
+	else
+	    set_hash("mday", INT2FIX(n2i(cs2,    0, 2)));
+	break;
+      case 4:
+	if (NIL_P(s3) && !NIL_P(s4)) {
+	    set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
+	    set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
+	}
+	else {
+	    set_hash("mon",  INT2FIX(n2i(cs2,    0, 2)));
+	    set_hash("mday", INT2FIX(n2i(cs2,    2, 2)));
+	}
+	break;
+      case 6:
+	if (NIL_P(s3) && !NIL_P(s4)) {
+	    set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
+	    set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
+	    set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
+	}
+	else {
+	    int                  y = n2i(cs2,    0, 2);
+	    if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
+		y = -y;
+	    set_hash("year", INT2FIX(y));
+	    set_hash("mon",  INT2FIX(n2i(cs2,    2, 2)));
+	    set_hash("mday", INT2FIX(n2i(cs2,    4, 2)));
+	}
+	break;
+      case 8:
+      case 10:
+      case 12:
+      case 14:
+	if (NIL_P(s3) && !NIL_P(s4)) {
+	    set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
+	    set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
+	    set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
+	    set_hash("mday", INT2FIX(n2i(cs2, l2-8, 2)));
+	    if (l2 >= 10)
+		set_hash("mon", INT2FIX(n2i(cs2, l2-10, 2)));
+	    if (l2 == 12) {
+		int y = n2i(cs2, l2-12, 2);
+		if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
+		    y = -y;
+		set_hash("year", INT2FIX(y));
+	    }
+	    if (l2 == 14) {
+		int y = n2i(cs2, l2-14, 4);
+		if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
+		    y = -y;
+		set_hash("year", INT2FIX(y));
+		set_hash("_comp", Qfalse);
+	    }
+	}
+	else {
+	    int                  y = n2i(cs2,    0, 4);
+	    if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
+		y = -y;
+	    set_hash("year", INT2FIX(y));
+	    set_hash("mon",  INT2FIX(n2i(cs2,    4, 2)));
+	    set_hash("mday", INT2FIX(n2i(cs2,    6, 2)));
+	    if (l2 >= 10)
+		set_hash("hour", INT2FIX(n2i(cs2,    8, 2)));
+	    if (l2 >= 12)
+		set_hash("min",  INT2FIX(n2i(cs2,   10, 2)));
+	    if (l2 >= 14)
+		set_hash("sec",  INT2FIX(n2i(cs2,   12, 2)));
+	    set_hash("_comp", Qfalse);
+	}
+	break;
+      case 3:
+	if (NIL_P(s3) && !NIL_P(s4)) {
+	    set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
+	    set_hash("min",  INT2FIX(n2i(cs2, l2-3, 1)));
+	}
+	else
+	    set_hash("yday", INT2FIX(n2i(cs2,    0, 3)));
+	break;
+      case 5:
+	if (NIL_P(s3) && !NIL_P(s4)) {
+	    set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
+	    set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
+	    set_hash("hour", INT2FIX(n2i(cs2, l2-5, 1)));
+	}
+	else {
+	    int                  y = n2i(cs2,    0, 2);
+	    if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
+		y = -y;
+	    set_hash("year", INT2FIX(y));
+	    set_hash("yday", INT2FIX(n2i(cs2,    2, 3)));
+	}
+	break;
+      case 7:
+	if (NIL_P(s3) && !NIL_P(s4)) {
+	    set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
+	    set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
+	    set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
+	    set_hash("mday", INT2FIX(n2i(cs2, l2-7, 1)));
+	}
+	else {
+	    int                  y = n2i(cs2,    0, 4);
+	    if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
+		y = -y;
+	    set_hash("year", INT2FIX(y));
+	    set_hash("yday", INT2FIX(n2i(cs2,    4, 3)));
+	}
+	break;
+    }
+    if (!NIL_P(s3)) {
+	cs3 = RSTRING_PTR(s3);
+	l3 = RSTRING_LEN(s3);
+
+	if (!NIL_P(s4)) {
+	    switch (l3) {
+	      case 2:
+	      case 4:
+	      case 6:
+		set_hash("sec", INT2FIX(n2i(cs3, l3-2, 2)));
+		if (l3 >= 4)
+		    set_hash("min", INT2FIX(n2i(cs3, l3-4, 2)));
+		if (l3 >= 6)
+		    set_hash("hour", INT2FIX(n2i(cs3, l3-6, 2)));
+		break;
+	    }
+	}
+	else {
+	    switch (l3) {
+	      case 2:
+	      case 4:
+	      case 6:
+		set_hash("hour", INT2FIX(n2i(cs3, 0, 2)));
+		if (l3 >= 4)
+		    set_hash("min", INT2FIX(n2i(cs3, 2, 2)));
+		if (l3 >= 6)
+		    set_hash("sec", INT2FIX(n2i(cs3, 4, 2)));
+		break;
+	    }
+	}
+    }
+    if (!NIL_P(s4)) {
+	l4 = RSTRING_LEN(s4);
+
+	set_hash("sec_fraction",
+		 rb_rational_new2(str2num(s4),
+				  f_expt(INT2FIX(10), LONG2NUM(l4))));
+    }
+    if (!NIL_P(s5)) {
+	VALUE zone_to_diff(VALUE s);
+	cs5 = RSTRING_PTR(s5);
+	l5 = RSTRING_LEN(s5);
+
+	set_hash("zone", s5);
+
+	if (*cs5 == '[') {
+	    char *buf = ALLOC_N(char, l5 + 1);
+	    char *s1, *s2, *s3;
+	    VALUE zone;
+
+	    memcpy(buf, cs5, l5);
+	    buf[l5 - 1] = '\0';
+
+	    s1 = buf + 1;
+	    s2 = index(buf, ':');
+	    if (s2) {
+		*s2 = '\0';
+		s2++;
+	    }
+	    if (s2)
+		s3 = s2;
+	    else
+		s3 = s1;
+	    zone = rb_str_new2(s3);
+	    set_hash("zone", zone);
+	    if (isdigit(*s1))
+		*--s1 = '+';
+	    set_hash("offset", zone_to_diff(rb_str_new2(s1)));
+	}
+    }
+
+    return 1;
+}
+
+static int
+parse_ddd(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+		"([-+]?)(\\d{2,14})"
+		  "(?:"
+		    "\\s*"
+		    "t?"
+		    "\\s*"
+		    "(\\d{2,6})?(?:[,.](\\d*))?"
+		  ")?"
+		  "(?:"
+		    "\\s*"
+		    "("
+		      "z\\b"
+		    "|"
+		      "[-+]\\d{1,4}\\b"
+		    "|"
+		      "\\[[-+]?\\d[^\\]]*\\]"
+		    ")"
+		")?";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_ddd_cb);
+}
+
+static int
+parse_bc_cb(VALUE m, VALUE hash)
+{
+    VALUE y;
+
+    y = ref_hash("year");
+    if (!NIL_P(y))
+	set_hash("year", f_add(f_negate(y), INT2FIX(1)));
+
+    return 1;
+}
+
+static int
+parse_bc(VALUE str, VALUE hash)
+{
+    static const char pat_source[] =
+	"\\b(bc\\b|bce\\b|b\\.c\\.|b\\.c\\.e\\.)";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_bc_cb);
+}
+
+static int
+parse_frag_cb(VALUE m, VALUE hash)
+{
+    VALUE s, n;
+
+    s = f_aref(m, INT2FIX(1));
+
+    if (!NIL_P(ref_hash("hour")) && NIL_P(ref_hash("mday"))) {
+	n = str2num(s);
+	if (f_ge_p(n, INT2FIX(1)) &&
+	    f_le_p(n, INT2FIX(31)))
+	    set_hash("mday", n);
+    }
+    if (!NIL_P(ref_hash("mday")) && NIL_P(ref_hash("hour"))) {
+	n = str2num(s);
+	if (f_ge_p(n, INT2FIX(0)) &&
+	    f_le_p(n, INT2FIX(24)))
+	    set_hash("hour", n);
+    }
+
+    return 1;
+}
+
+static int
+parse_frag(VALUE str, VALUE hash)
+{
+    static const char pat_source[] = "\\A\\s*(\\d{1,2})\\s*\\z";
+    static VALUE pat = Qnil;
+
+    REGCOMP_I(pat);
+    SUBS(str, pat, parse_frag_cb);
+}
+
+#define HAVE_ALPHA (1<<0)
+#define HAVE_DIGIT (1<<1)
+#define HAVE_DASH (1<<2)
+#define HAVE_DOT (1<<3)
+#define HAVE_SLASH (1<<4)
+
+static unsigned
+check_class(VALUE s)
+{
+    unsigned flags;
+    long i;
+
+    flags = 0;
+    for (i = 0; i < RSTRING_LEN(s); i++) {
+	if (isalpha(RSTRING_PTR(s)[i]))
+	    flags |= HAVE_ALPHA;
+	if (isdigit(RSTRING_PTR(s)[i]))
+	    flags |= HAVE_DIGIT;
+	if (RSTRING_PTR(s)[i] == '-')
+	    flags |= HAVE_DASH;
+	if (RSTRING_PTR(s)[i] == '.')
+	    flags |= HAVE_DOT;
+	if (RSTRING_PTR(s)[i] == '/')
+	    flags |= HAVE_SLASH;
+    }
+    return flags;
+}
+
+#define HAVE_ALPHA_P() (check_class(str) & HAVE_ALPHA)
+#define HAVE_DIGIT_P() (check_class(str) & HAVE_DIGIT)
+#define HAVE_ELEM_P(x) ((check_class(str) & (x)) == (x))
+
+VALUE
+date__parse(VALUE str, VALUE comp)
+{
+    VALUE zone_to_diff(VALUE s);
+    VALUE backref, hash;
+
+    backref = rb_backref_get();
+    rb_match_busy(backref);
+
+    {
+	static const char pat_source[] = "[^-+',./:@[:alnum:]\\[\\]]+";
+	static VALUE pat = Qnil;
+
+	str = rb_str_dup(str);
+	REGCOMP_0(pat);
+	f_gsub_bang(str, pat, rb_str_new(" ", 1));
+    }
+
+    hash = rb_hash_new();
+    set_hash("_comp", comp);
+
+    if (HAVE_ELEM_P(HAVE_ALPHA))
+	parse_day(str, hash);
+    if (HAVE_ELEM_P(HAVE_DIGIT))
+	parse_time(str, hash);
+
+    if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT))
+	if (parse_eu(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT))
+	if (parse_us(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DASH))
+	if (parse_iso(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT))
+	if (parse_jis(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_DASH))
+	if (parse_vms(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_SLASH))
+	if (parse_sla(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT))
+	if (parse_dot(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT))
+	if (parse_iso2(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT))
+	if (parse_year(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_ALPHA))
+	if (parse_mon(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT))
+	if (parse_mday(str, hash))
+	    goto ok;
+    if (HAVE_ELEM_P(HAVE_DIGIT))
+	if (parse_ddd(str, hash))
+	    goto ok;
+
+  ok:
+    if (HAVE_ELEM_P(HAVE_ALPHA))
+	parse_bc(str, hash);
+    if (HAVE_ELEM_P(HAVE_DIGIT))
+	parse_frag(str, hash);
+
+    {
+	if (RTEST(ref_hash("_comp"))) {
+	    VALUE y;
+
+	    y = ref_hash("cwyear");
+	    if (!NIL_P(y))
+		if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
+		    if (f_ge_p(y, INT2FIX(69)))
+			set_hash("cwyear", f_add(y, INT2FIX(1900)));
+		    else
+			set_hash("cwyear", f_add(y, INT2FIX(2000)));
+		}
+	    y = ref_hash("year");
+	    if (!NIL_P(y))
+		if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
+		    if (f_ge_p(y, INT2FIX(69)))
+			set_hash("year", f_add(y, INT2FIX(1900)));
+		    else
+			set_hash("year", f_add(y, INT2FIX(2000)));
+		}
+	}
+    }
+
+    del_hash("_comp");
+
+    {
+	VALUE zone = ref_hash("zone");
+	if (!NIL_P(zone) && NIL_P(ref_hash("offset")))
+	    set_hash("offset", zone_to_diff(zone));
+    }
+
+    rb_backref_set(backref);
+
+    return hash;
+}
+
+/*
+Local variables:
+c-file-style: "ruby"
+End:
+*/

Property changes on: ext/date/date_parse.c
___________________________________________________________________
Added: svn:mime-type
   + text/plain


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]