How do I change the zone offset for a time in Ruby on Rails?

前端 未结 13 2343
感情败类
感情败类 2020-12-30 22:03

I have a variable foo that contains a time, lets say 4pm today, but the zone offset is wrong, i.e. it is in the wrong time zone. How do I change the time zone?

When

相关标签:
13条回答
  • 2020-12-30 22:09

    This takes advantage of the fact that Time#asctime doesn't include the zone.

    Given a time:

    >> time = Time.now
    => 2013-03-13 13:01:48 -0500
    

    Force it to another zone (this returns an ActiveSupport::TimeWithZone):

    >> ActiveSupport::TimeZone['US/Pacific'].parse(time.asctime)
    => Wed, 13 Mar 2013 13:01:48 PDT -07:00
    

    Note that the original zone is ignored completely. If I convert the original time to utc, the result will be different:

    >> ActiveSupport::TimeZone['US/Pacific'].parse(time.getutc.asctime)
    => Wed, 13 Mar 2013 18:01:48 PDT -07:00
    

    You can use to_time or to_datetime on the result to get a corresponding Time or DateTime.

    This question uses an interesting approach with DateTime#change to set the tz offset. (Remember that ActiveSupport makes it easy to convert between Time and DateTime.) The downside is that there's no DST detection; you have to do that manually by using TZInfo's current_period.

    0 讨论(0)
  • 2020-12-30 22:10

    ...

    >> Time.at(Time.now.utc + Time.zone_offset('PST'))
    => Mon Jun 07 22:46:22 UTC 2010
    >> Time.at(Time.now.utc + Time.zone_offset('PDT'))
    => Mon Jun 07 23:46:26 UTC 2010
    >> Time.at(Time.now.utc + Time.zone_offset('CST'))
    => Tue Jun 08 00:46:32 UTC 2010
    

    One note: make sure that the current time object is set to UTC time first, otherwise Ruby will try and convert the Time object to your local timezone, thus throwing the calculation. You can always get the adjusted time by applying ".utc" to the end of the above statements in that case.

    0 讨论(0)
  • 2020-12-30 22:11

    When Parsing a Time

    I'd be interested to hear how you're setting the variable foo to begin with.

    If you're parsing a time string that doesn't have a time zone (what I was doing during a data import) then you can use String#in_time_zone to force the time zone during the parsing:

    "Fri Jun 26 2019 07:00:00".in_time_zone( "Eastern Time (US & Canada)" ) 
    # => Wed, 26 Jun 2019 07:00:00 EDT -04:00
    

    Works like a charm and is super clean.

    0 讨论(0)
  • 2020-12-30 22:13

    It's probably a good idea to store the time as UTC and then show it in a specific time zone when it is displayed. Here's an easy way to do that (works in Rails 4, unsure about earlier versions).

    t = Time.now.utc
    
    => 2016-04-19 20:18:33 UTC
    
    t.in_time_zone("EST")
    
    => Tue, 19 Apr 2016 15:18:33 EST -05:00
    

    But if you really want to store it in a specific timezone, you can just set the initial Time object to itself.in_time_zone like this:

    t = t.in_time_zone("EST")
    
    0 讨论(0)
  • 2020-12-30 22:14

    For those that came across this while looking for a non-rails solution (as I did), TZInfo solved it for me...

    require 'tzinfo'
    def adjust_time time, time_zone="America/Los_Angeles"
        return TZInfo::Timezone.get(time_zone).utc_to_local(time.utc)
    end
    
    puts adjust_time(Time.now) 
    #=> PST or PDT
    puts adjust_time(Time.now, "America/New_York")
    #=> EST or EDT
    

    This also handles DST, which is what I needed that wasn't handled above.

    See: http://tzinfo.rubyforge.org/

    0 讨论(0)
  • 2020-12-30 22:14

    I'm using Rails 2.0 before they added the code that makes weppos solution work. Here's what I did

    # Silly hack, because sometimes the input_date is in the wrong timezone
    temp = input_date.to_time.to_a
    temp[8] = true
    temp[9] = "Eastern Daylight Time"
    input_date = Time.local(*temp)
    

    I break the time down into a 10 element array, change the timezone and then convert the array back into a time.

    0 讨论(0)
提交回复
热议问题