124

In Ruby/Rails, how do I convert a UTC DateTime to another time zone?

fearless_fool
  • 33,645
  • 23
  • 135
  • 217
Drew Johnson
  • 18,973
  • 9
  • 32
  • 35

6 Answers6

228
time.in_time_zone(time_zone)

Example:

zone = ActiveSupport::TimeZone.new("Central Time (US & Canada)")
Time.now.in_time_zone(zone)

or just

Time.now.in_time_zone("Central Time (US & Canada)")

You can find the names of the ActiveSupport time zones by doing:

ActiveSupport::TimeZone.all.map(&:name)
# or for just US
ActiveSupport::TimeZone.us_zones.map(&:name)
mckeed
  • 9,719
  • 2
  • 37
  • 41
  • In irb, when I try Time.now.in_time_zone('CST'), I get the error "undefined method 'in_time_zone'". Are there rails classes that I need in order to get this to work? – Drew Johnson Apr 23 '10 at 02:59
  • Which version of Rails are you using? Does it work if you do Time.zone.now.in_time_zone(...)? – mckeed Apr 23 '10 at 14:49
  • 17
    To use this outside Rails, `require 'active_support/time'` first. – sunaku Jan 18 '12 at 17:50
  • 3
    You can list all time zones by running `rake time:zones:all`. Also see `rake -D time`. Set the default time zone in `config/application.rb`. – user664833 Apr 05 '12 at 03:58
  • 1
    @AdamEberlin In Rails you usually use ActiveSupport::TimeWithZone, not DateTime. All this code works on ruby DateTime objects as well as Time objects. – mckeed Jun 06 '12 at 21:36
  • Hmm, okay. Thanks for the info. I was doing this in plain ruby, not in RAILS (for once), so perhaps they do differ in behavior. I'll remove my previous comment. – Adam Eberlin Jun 07 '12 at 14:41
  • 1
    You can also get a list of all time zones from the [ActiveSupport::TimeZone documentation](http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html) page. – sameers Jul 22 '15 at 15:42
  • For GMT use `in_time_zone('GMT')`. Easy! – Dennis Hackethal Jan 15 '22 at 03:48
9

if Time.zone it's your desired time zone then you can use @date.to_time.to_datetime

> @date
=> Tue, 02 Sep 2014 23:59:59 +0000
> @date.class
=> DateTime
> @date.to_time
=> 2014-09-02 12:59:59 -1100
> @date.to_time.to_datetime
=> Tue, 02 Sep 2014 12:59:59 -1100 
vladCovaliov
  • 4,333
  • 2
  • 43
  • 58
  • 2
    Doesn't work on Rails 5 ` Time.zone # => Europe/Paris my_date # => Wed, 29 Mar 2017 19:00:20 +0200 my_date.to_time # => "2017-03-29T17:00:20.000+00:00" my_date.to_time.to_datetime # => Wed, 29 Mar 2017 17:00:20 +0000 ` – Cyril Duchon-Doris Mar 21 '17 at 10:36
5

In plain ruby, with only require 'date', use the new_offset method:

require 'date'

d=DateTime.parse('2000-01-01 12:00 +0200')
l=d.new_offset('-0700')
u=l.new_offset('UTC')
puts "#{u.strftime('%a %F %T %Z')} ❖ #{l.strftime('%a %F %T %Z')}"

Tested with ruby 2.3.7 that came standard on Mac OS X 10.13.

jbyler
  • 7,200
  • 3
  • 34
  • 42
3

Just in case, if you are dealing with ActiveRecord object in Rails.

It might be a good idea to use Time.use_zone for a per request basis timezone that overrides the default timezone set in config.time_zone

More details I explain at https://stackoverflow.com/a/25055692/542995

Community
  • 1
  • 1
zdk
  • 1,528
  • 11
  • 17
3

Try ActiveSupport's TimeWithZone objects manipulated with TimeZone. ActiveSupport also provides the in_time_zone method for converting a UTC time to a specified TimeZone time zone. mckeed's answer shows the code.

Fred
  • 8,582
  • 1
  • 21
  • 27
  • What's the syntax for importing TimeWithZone into my class? Or do I get it by default with Rails? – Drew Johnson Apr 23 '10 at 03:04
  • 1
    I believe you get it by default. mckeed has the code you need, but you won't see it in irb. You need to run it in Rails. – Fred Apr 23 '10 at 04:32
  • You're right - thanks, Fred - it does come with Rails by default. I was grasping at straws, trying to get it working in irb. – Drew Johnson Apr 23 '10 at 19:21
0

I'm using simple_form in Rails 4 and I just added the input field as

<%= f.input :time_zone, :as => :time_zone %>

with the migration

class AddTimeZoneColumnToTextmessage < ActiveRecord::Migration
  def change
    add_column :textmessages, :time_zone, :string
  end
end
maudulus
  • 10,627
  • 10
  • 78
  • 117