45

I have set the time zone in /config/application.rb, and I expect all times generated in my app to be in this time zone by default, yet when I create a new DateTime object (using .new), it creates it in GMT. How can I get it to be in my app's time zone?

config/application.rb

config.time_zone = 'Pacific Time (US & Canada)'

irb

DateTime.now
# => Wed, 11 Jul 2012 19:04:56 -0700 

mydate = DateTime.new(2012, 07, 11, 20, 10, 0)
# => Wed, 11 Jul 2012 20:10:00 +0000                    # GMT, but I want PDT

Using in_time_zone doesn't work because that just converts the GMT time to PDT time, which is the wrong time:

mydate.in_time_zone('Pacific Time (US & Canada)')
# => Wed, 11 Jul 2012 13:10:00 PDT -07:00               # wrong time (I want 20:10)
BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
user664833
  • 18,397
  • 19
  • 91
  • 140

6 Answers6

41

You can use ActiveSupport's TimeWithZone (Time.zone) object to create and parse dates in the time zone of your application:

1.9.3p0 :001 > Time.zone.now
 => Wed, 11 Jul 2012 19:47:03 PDT -07:00 
1.9.3p0 :002 > Time.zone.parse('2012-07-11 21:00')
 => Wed, 11 Jul 2012 21:00:00 PDT -07:00 
Peter Brown
  • 50,956
  • 18
  • 113
  • 146
  • 3
    This is really helpful! But what if you want to create a Time in a zone different than what you have set config.time_zone= to in config/application.rb? – idrinkpabst Jul 31 '13 at 22:28
  • I would use something like `'2012-07-11 21:00'.to_datetime.in_time_zone('Eastern Time (US & Canada)')` – Peter Brown Aug 01 '13 at 01:05
  • 4
    this actually doesn't work. let's say you want to create a Time in zone for 9am Eastern. if you do '2012-07-11 09:00'.to_datetime.in_time_zone('Eastern Time (US & Canada)'), this gives you back the wrong time because it's converting from UTC. if you do '2012-07-11 09:00 Eastern Time (US & Canada)'.to_datetime.in_time_zone('Eastern Time (US & Canada)') this still doesn't work because DateTime is screwy when it comes to daylight savings time. Best to avoid DateTime completely. Any ideas? – idrinkpabst Aug 01 '13 at 20:01
13

Another way without string parsing:

irb> Time.zone.local(2012, 7, 11, 21)
=> Wed, 07 Nov 2012 21:00:00 PDT -07:00
hangsu
  • 507
  • 4
  • 14
  • The arguments are different from `DatTime.new` method. Time.zone.local doesn't accept 0 or -1 as arguments and will give Argument out of range error. – Tun Mar 29 '18 at 14:49
7

If I have it, I usually just specify the utc_offset when instantiating Time.new or DateTime.new.

[1] pry(main)> Time.new(2013,01,06, 11, 25, 00) #no specified utc_offset defaults to system time
 => 2013-01-06 11:25:00 -0500
[2] pry(main)> Time.new(2013,01,06, 11, 25, 00, "+00:00") #UTC
 => 2013-01-06 11:25:00 +0000
[3] pry(main)> Time.new(2013,01,06, 11, 25, 00, "-08:00") #PST
 => 2013-01-06 11:25:00 -0800 
ewH
  • 2,553
  • 2
  • 20
  • 13
5

If you want to create a DateTime in a local timezone different than what is set as config.time_zone:

la_date = ActiveSupport::TimeZone["America/Los_Angeles"].parse('2020-02-01')
DateTime.new(la_date.year, la_date.month, la_date.day, la_date.hour, la_date.min, la_date.sec, la_date.zone)
Michael Hagar
  • 626
  • 5
  • 20
  • 1
    If you don't want to parse, you can also use `local`. E.g. `ActiveSupport::TimeZone["America/Los_Angeles"].local(2020, 1, 1, 12, 0).to_datetime` – Chad M Oct 19 '20 at 01:43
2

This can be achieved in the DateTime class as well by including the timezone.

2.5.1 :001 > require 'rails'
 => true
2.5.1 :002 > mydate = DateTime.new(2012, 07, 11, 20, 10, 0)
 => Wed, 11 Jul 2012 20:10:00 +0000
2.5.1 :003 > mydate = DateTime.new(2012, 07, 11, 20, 10, 0, "PST")
 => Wed, 11 Jul 2012 20:10:00 -0800

or

https://docs.ruby-lang.org/en/2.6.0/DateTime.html

2.6.0 :001 > DateTime.new(2012, 07, 11, 20, 10, 0, "-06")
 => Wed, 11 Jul 2012 20:10:00 -0600
2.6.0 :002 > DateTime.new(2012, 07, 11, 20, 10, 0, "-05")
 => Wed, 11 Jul 2012 20:10:00 -0500
JustJonG
  • 21
  • 3
0

I do the following in ApplicationController to set the timezone to the user's time.

I'm not sure if this is what you want.

class ApplicationController < ActionController::Base
  before_filter :set_timezone
  def set_timezone
    # current_user.time_zone #=> 'London'
    Time.zone = current_user.time_zone if current_user && current_user.time_zone
  end

end
drhenner
  • 2,200
  • 18
  • 23