W
Will Rogers
The date parsing code in the Ruby stdlib (date/format.rb) does not
parse strings with long timezones, e.g. "Eastern Daylight Time", as
opposed to the abbreviated "EDT". On win32, Time#to_s produces a
string with the long timezone name. So, Time.parse(Time.now.to_s)
assumes the current year, and DateTime.parse(Time.now.to_s) throws an
error.
This is a critical issue for me because it is causing crashes in a
production Rails application during XML serialization in
ActionWebService.
For example:
irb(main):012:0> Time.now.to_s
=> "Tue May 16 09:27:36 Eastern Daylight Time 2006"
irb(main):013:0> Time.parse Time.now.to_s
=> Tue May 16 09:27:46 Eastern Daylight Time 2006
irb(main):014:0> Time.parse 'Mon May 16 09:27:46 Eastern Daylight Time
2005'
=> Tue May 16 09:27:46 Eastern Daylight Time 2006
irb(main):001:0> Date._parse Time.now.to_s
=> {:hour=>10, :wday=>2, :mday=>16, :mon=>5, :zone=>"Eastern",
:sec=>13, :min=>8}
irb(main):015:0> DateTime.parse Time.now.to_s
ArgumentError: 3 elements of civil date are necessary
from c:/ruby/lib/ruby/1.8/date.rb:1214:in `new_with_hash'
from c:/ruby/lib/ruby/1.8/date.rb:1258:in `parse'
from (irb):15
(note the change of year from 2005 -> 2006 in lines 5 -> 6)
H:\>ruby -v
ruby 1.8.4 (2005-12-24) [i386-mswin32]
There was a previous mention of this problem here, and Ara Howard
indicated that it was fixed in 1.9:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/161521
However, since his example "works" in 1.8.4 also, because of the year
assumption demonstrated above, I am inclined to think that it actually
is not fixed, and Ara's example is a false positive, so to speak.
The fact that I was unable to find any revisions in the official Ruby
CVS addressing this problem reinforces that conclusion. If anyone
knows for sure whether this has been fixed or not, please point me to
the specific revision(s) in CVS.
I believe the relevant code is this regexp, beginning at
date/format.rb:261.
if str.sub!(
/(\d+)\d+)
(?:
\d+)(?:[,.](\d*))?
)?
(?:
\s*
([ap])(?:m\b|\.m\.)
)?
(?:
\s*
(
[a-z]+(?:\s+dst)?\b
|
[-+]\d+(?::?\d+)
)
)?
/inox,
' ')
You can see how in the last group, [a-z]+(?:\s+dst)?\b will match "EDT"
or "Eastern" (as in the example above), but not "Eastern Standard
Time". But, I am hardly familiar with the inner workings of the Ruby
stdlib, so I could be wrong. If anyone who knows more could take a
look at this, it would be much appreciated.
- Will
parse strings with long timezones, e.g. "Eastern Daylight Time", as
opposed to the abbreviated "EDT". On win32, Time#to_s produces a
string with the long timezone name. So, Time.parse(Time.now.to_s)
assumes the current year, and DateTime.parse(Time.now.to_s) throws an
error.
This is a critical issue for me because it is causing crashes in a
production Rails application during XML serialization in
ActionWebService.
For example:
irb(main):012:0> Time.now.to_s
=> "Tue May 16 09:27:36 Eastern Daylight Time 2006"
irb(main):013:0> Time.parse Time.now.to_s
=> Tue May 16 09:27:46 Eastern Daylight Time 2006
irb(main):014:0> Time.parse 'Mon May 16 09:27:46 Eastern Daylight Time
2005'
=> Tue May 16 09:27:46 Eastern Daylight Time 2006
irb(main):001:0> Date._parse Time.now.to_s
=> {:hour=>10, :wday=>2, :mday=>16, :mon=>5, :zone=>"Eastern",
:sec=>13, :min=>8}
irb(main):015:0> DateTime.parse Time.now.to_s
ArgumentError: 3 elements of civil date are necessary
from c:/ruby/lib/ruby/1.8/date.rb:1214:in `new_with_hash'
from c:/ruby/lib/ruby/1.8/date.rb:1258:in `parse'
from (irb):15
(note the change of year from 2005 -> 2006 in lines 5 -> 6)
H:\>ruby -v
ruby 1.8.4 (2005-12-24) [i386-mswin32]
There was a previous mention of this problem here, and Ara Howard
indicated that it was fixed in 1.9:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/161521
However, since his example "works" in 1.8.4 also, because of the year
assumption demonstrated above, I am inclined to think that it actually
is not fixed, and Ara's example is a false positive, so to speak.
The fact that I was unable to find any revisions in the official Ruby
CVS addressing this problem reinforces that conclusion. If anyone
knows for sure whether this has been fixed or not, please point me to
the specific revision(s) in CVS.
I believe the relevant code is this regexp, beginning at
date/format.rb:261.
if str.sub!(
/(\d+)\d+)
(?:
\d+)(?:[,.](\d*))?
)?
(?:
\s*
([ap])(?:m\b|\.m\.)
)?
(?:
\s*
(
[a-z]+(?:\s+dst)?\b
|
[-+]\d+(?::?\d+)
)
)?
/inox,
' ')
You can see how in the last group, [a-z]+(?:\s+dst)?\b will match "EDT"
or "Eastern" (as in the example above), but not "Eastern Standard
Time". But, I am hardly familiar with the inner workings of the Ruby
stdlib, so I could be wrong. If anyone who knows more could take a
look at this, it would be much appreciated.
- Will