How do I alter the timezone of a DateTime in Ruby?

50,792

Solution 1

Using Rails 3, you're looking for DateTime.change()

dt = DateTime.now
=> Mon, 20 Dec 2010 18:59:43 +0100
dt = dt.change(:offset => "+0000")
=> Mon, 20 Dec 2010 18:59:43 +0000

Solution 2

Using a number offset e.g. '+1000' wont work all year round because of daylight savings. Checkout ActiveSupport::TimeZone. More info here

Solution 3

As @Sam pointed out, changing offset is not sufficient and would lead to errors. In order to be resistant to DST clock advancements, the conversion should be done in a following way:

d = datetime_to_alter_time_zone
time_zone = 'Alaska'

DateTime.new
  .in_time_zone(time_zone)
  .change(year: d.year, month: d.month, day: d.day, hour: d.hour, min: d.min, sec: d.sec)

Solution 4

d = DateTime.now
puts [ d, d.zone ]
#=> 2010-12-17T13:28:29-07:00
#=> -07:00

d2 = d.new_offset(3.0/24)
puts d2, d2.zone
#=> 2010-12-17T23:28:29+03:00
#=> +03:00

Edit: This answer doesn't account for the information provided by comment to another answer that the desire is to have the reported 'hours' be the same after the time zone change.

Solution 5

I would use a Time object instead. So get the current local time then increment it by the UTC offset and convert to UTC, like so:

t = Time.now # or Time.parse(myDateTime.asctime)
t # => Thu Dec 16 21:07:48 -0800 2010
(t + t.utc_offset).utc # => Thu Dec 16 21:07:48 UTC 2010

Although, per Phrogz comment, if you just want to store timestamps in a location independent way then just use the current UTC time:

Time.now.utc
Share:
50,792
Daniel Beardsley
Author by

Daniel Beardsley

I'm an independent Web Developer located on the Central Coast of California. I mostly develop using Ruby on Rails, but have been trying out Sinatra, Node.js, and other fun things as of late.

Updated on July 16, 2020

Comments

  • Daniel Beardsley
    Daniel Beardsley almost 4 years

    Reading, writing, and serializing dates and times while keeping the time zone constant is becoming annoying. I'm using Ruby (and Rails 3.0) and am trying to alter the time zone of a DateTime. (to UTC) but not the time itself.

    I want this:

    t = DateTime.now
    t.hour
    -> 4
    t.offset = 0
    t.hour
    -> 4
    t.utc?
    -> true
    

    The closest I have come is this, but it's not intuitive.

    t = DateTime.now
    t.hour
    -> 4
    t += t.offset
    t = t.utc
    t.hour
    -> 4
    t.utc?
    -> true
    

    Is there any better way?