Search code examples
ruby-on-railsrubytimezoneactivesupport

Convert UTC to User-Defined Time Zone with ActiveSupport::TimeWithZone


I'm needing to convert a UTC time to the equivalent time in the user's time zone as part of a Rake task. What I want to do is change a UTC timestamp for midnight and re-create the timestamp to be midnight in the time zone of the user.

Example

Convert a UTC time

Wed, 01 Mar 2017 00:00:00 UTC +00:00

to Eastern Daylight Time (EDT) when observing daylight saving time (spring/summer)

Wed, 01 Mar 2017 04:00:00 UTC +00:00
zone = ActiveSupport::TimeZone.new("Eastern Time (US & Canada)")
time = "Wed, 01 Mar 2017 00:00:00 UTC +00:00"
time.in_time_zone(zone)
=> Tue, 28 Feb 2017 19:00:00.000000000 EST -05:00

The above will still save as Wed, 01 Mar 2017 00:00:00 UTC +00:00 in the database, as Rails will convert all timestamps back to UTC. However, I'm needing to get Wed, 01 Mar 2017 04:00:00 UTC +00:00 as that is the true beginning of the day in the user's time zone.


Solution

  • You can parse a string relative to a timezone via ActiveSupport::TimeZone#parse. Just make sure to omit any time zone specifiers like "UTC +00:00":

    zone = ActiveSupport::TimeZone.new("Eastern Time (US & Canada)")
    
    time = zone.parse("Wed, 01 Mar 2017 00:00:00")
    #=> Wed, 01 Mar 2017 00:00:00.000000000 EST -05:00
    
    time.utc
    #=> 2017-03-01 05:00:00 UTC
    

    The last call to utc is just for illustration purposes, Rails will perform this conversion automatically when saving time to the database.

    With numeric input:

    time = zone.local(2017, 3, 1)
    #=> Wed, 01 Mar 2017 00:00:00.000000000 EST -05:00