Skip to content

Commit 21ca4a4

Browse files
committed
Add support for ordinal date values in AS::TimeZone.iso8601
Date._iso8601 will attempt to parse certain args as ordinal dates eg. '21087' => 2021-03-28. Add ActiveSupport::TimeZone.iso8601 support for these ordinal values to be consistent with Date._iso8601 and raise ArgumentError where the day of year is invalid.
1 parent 0ffdf6d commit 21ca4a4

File tree

3 files changed

+36
-6
lines changed

3 files changed

+36
-6
lines changed

activesupport/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
* `TimeZone.iso8601` now accepts valid ordinal values similar to Ruby's `Date._iso8601` method.
2+
A valid ordinal value will be converted to an instance of `TimeWithZone` using the `:year`
3+
and `:yday` fragments returned from `Date._iso8601`.
4+
5+
```ruby
6+
twz = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].iso8601("21087")
7+
twz.to_a[0, 6] == [0, 0, 0, 28, 03, 2021]
8+
```
9+
10+
*Steve Laing*
11+
112
* `Time#change` and methods that call it (eg. `Time#advance`) will now
213
return a `Time` with the timezone argument provided, if the caller was
314
initialized with a timezone argument.

activesupport/lib/active_support/values/time_zone.rb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,10 +387,21 @@ def at(*args)
387387
def iso8601(str)
388388
parts = Date._iso8601(str)
389389

390+
year = parts.fetch(:year)
391+
392+
if parts.key?(:yday)
393+
ordinal_date = Date.ordinal(year, parts.fetch(:yday))
394+
month = ordinal_date.month
395+
day = ordinal_date.day
396+
else
397+
month = parts.fetch(:mon)
398+
day = parts.fetch(:mday)
399+
end
400+
390401
time = Time.new(
391-
parts.fetch(:year),
392-
parts.fetch(:mon),
393-
parts.fetch(:mday),
402+
year,
403+
month,
404+
day,
394405
parts.fetch(:hour, 0),
395406
parts.fetch(:min, 0),
396407
parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
@@ -403,7 +414,7 @@ def iso8601(str)
403414
TimeWithZone.new(nil, self, time)
404415
end
405416

406-
rescue KeyError
417+
rescue Date::Error, KeyError
407418
raise ArgumentError, "invalid date"
408419
end
409420

activesupport/test/time_zone_test.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,19 @@ def test_iso8601_with_ambiguous_time
365365
assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.parse("2014-10-26T01:00:00")
366366
end
367367

368-
def test_iso8601_with_invalid_value_parseable_by_date__iso8601
368+
def test_iso8601_with_ordinal_date_value
369+
zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
370+
371+
twz = zone.iso8601("21087")
372+
assert_equal Time.utc(2021, 3, 28, 0, 0, 0), twz.time
373+
assert_equal zone, twz.time_zone
374+
end
375+
376+
def test_iso8601_with_invalid_ordinal_date_value
369377
zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
370378

371379
exception = assert_raises(ArgumentError) do
372-
zone.iso8601("12936")
380+
zone.iso8601("21367")
373381
end
374382

375383
assert_equal "invalid date", exception.message

0 commit comments

Comments
 (0)