1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31322 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
tadf 2011-04-23 12:31:15 +00:00
parent d5b4cf7f79
commit 448e0d6668
4 changed files with 1463 additions and 598 deletions

View file

@ -1,3 +1,10 @@
Sat Apr 23 21:29:42 2011 Tadayoshi Funaba <tadf@dotrb.org>
* 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@ruby-lang.org>
* array.c (rb_ary_sort_bang): fix rdoc.

View file

@ -1417,7 +1417,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
/*
* call-seq:
* Date._strptime(string, [format="%F"])
* Date._strptime(string[, format="%F"])
*
* Return a hash of parsed elements.
*/
@ -1427,6 +1427,50 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass)
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
@ -3155,7 +3199,7 @@ datetime_s_now(int argc, VALUE *argv, VALUE klass)
/*
* 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 @@ Init_date_core(void)
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);

1349
ext/date/date_parse.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -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 @@ class Date
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 @@ class Date
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 @@ class Date
(?: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 @@ class Date
\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 @@ class Date
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'
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
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
end
offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
offset *= -1 if sign == '-'
end
offset
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
if (zone.size % 2) == 1
hour = zone[0,1]
min = zone[1,2]
sec = zone[3,2]
else
hour = zone[0,2]
min = zone[2,2]
sec = zone[4,2]
end
end
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