Skip to content

Commit a5e507f

Browse files
pjungwirpixeltrix
authored andcommitted
Add ActiveSupport::TimeZone#strptime.
This makes it easier to parse user-inputted times as from a given time zone.
1 parent 9a034bc commit a5e507f

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

activesupport/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
* Added `ActiveSupport::TimeZone#strptime` to allow parsing times as if
2+
from a given timezone.
3+
4+
*Paul A Jungwirth*
5+
16
* `ActiveSupport::Callbacks#skip_callback` now raises an `ArgumentError` if
27
an unrecognized callback is removed.
38

activesupport/lib/active_support/values/time_zone.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,26 @@ def parse(str, now=now())
368368
end
369369
end
370370

371+
# Parses +str+ according to +spec+ and returns an ActiveSupport::TimeWithZone.
372+
#
373+
# Assumes that +str+ is a time in the time zone +self+,
374+
# unless +spec+ includes an explicit time zone.
375+
# (This is the same behavior as +parse+.)
376+
# In either case, the returned TimeWithZone has the timezone of +self+.
377+
#
378+
# Time.zone = 'Hawaii' # => "Hawaii"
379+
# Time.zone.strptime('1999-12-31 14:00:00', '%Y-%m-%d %H:%M:%S') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
380+
#
381+
def strptime(str, spec)
382+
case spec
383+
when /(^|[^%](%%)*)%(Z|:{0,3}z)/
384+
DateTime.strptime(str, spec).in_time_zone(self)
385+
else
386+
t = DateTime.strptime(str, spec)
387+
local(t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec)
388+
end
389+
end
390+
371391
# Returns an ActiveSupport::TimeWithZone instance representing the current
372392
# time in the time zone represented by +self+.
373393
#

activesupport/test/time_zone_test.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,71 @@ def test_parse_handles_dst_jump
311311
end
312312
end
313313

314+
def test_strptime
315+
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
316+
twz = zone.strptime('1999-12-31 12:00:00', '%Y-%m-%d %H:%M:%S')
317+
assert_equal Time.utc(1999,12,31,17), twz
318+
assert_equal Time.utc(1999,12,31,12), twz.time
319+
assert_equal Time.utc(1999,12,31,17), twz.utc
320+
assert_equal zone, twz.time_zone
321+
end
322+
323+
def test_strptime_with_nondefault_time_zone
324+
with_tz_default ActiveSupport::TimeZone['Pacific Time (US & Canada)'] do
325+
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
326+
twz = zone.strptime('1999-12-31 12:00:00', '%Y-%m-%d %H:%M:%S')
327+
assert_equal Time.utc(1999,12,31,17), twz
328+
assert_equal Time.utc(1999,12,31,12), twz.time
329+
assert_equal Time.utc(1999,12,31,17), twz.utc
330+
assert_equal zone, twz.time_zone
331+
end
332+
end
333+
334+
def test_strptime_with_explicit_time_zone_as_abbrev
335+
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
336+
twz = zone.strptime('1999-12-31 12:00:00 PST', '%Y-%m-%d %H:%M:%S %Z')
337+
assert_equal Time.utc(1999,12,31,20), twz
338+
assert_equal Time.utc(1999,12,31,15), twz.time
339+
assert_equal Time.utc(1999,12,31,20), twz.utc
340+
assert_equal zone, twz.time_zone
341+
end
342+
343+
def test_strptime_with_explicit_time_zone_as_h_offset
344+
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
345+
twz = zone.strptime('1999-12-31 12:00:00 -08', '%Y-%m-%d %H:%M:%S %:::z')
346+
assert_equal Time.utc(1999,12,31,20), twz
347+
assert_equal Time.utc(1999,12,31,15), twz.time
348+
assert_equal Time.utc(1999,12,31,20), twz.utc
349+
assert_equal zone, twz.time_zone
350+
end
351+
352+
def test_strptime_with_explicit_time_zone_as_hm_offset
353+
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
354+
twz = zone.strptime('1999-12-31 12:00:00 -08:00', '%Y-%m-%d %H:%M:%S %:z')
355+
assert_equal Time.utc(1999,12,31,20), twz
356+
assert_equal Time.utc(1999,12,31,15), twz.time
357+
assert_equal Time.utc(1999,12,31,20), twz.utc
358+
assert_equal zone, twz.time_zone
359+
end
360+
361+
def test_strptime_with_explicit_time_zone_as_hms_offset
362+
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
363+
twz = zone.strptime('1999-12-31 12:00:00 -08:00:00', '%Y-%m-%d %H:%M:%S %::z')
364+
assert_equal Time.utc(1999,12,31,20), twz
365+
assert_equal Time.utc(1999,12,31,15), twz.time
366+
assert_equal Time.utc(1999,12,31,20), twz.utc
367+
assert_equal zone, twz.time_zone
368+
end
369+
370+
def test_strptime_with_almost_explicit_time_zone
371+
zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
372+
twz = zone.strptime('1999-12-31 12:00:00 %Z', '%Y-%m-%d %H:%M:%S %%Z')
373+
assert_equal Time.utc(1999,12,31,17), twz
374+
assert_equal Time.utc(1999,12,31,12), twz.time
375+
assert_equal Time.utc(1999,12,31,17), twz.utc
376+
assert_equal zone, twz.time_zone
377+
end
378+
314379
def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize
315380
tzinfo = TZInfo::Timezone.get('America/New_York')
316381
zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo)

0 commit comments

Comments
 (0)