Rails daylight savings time not accounted for when using DateTime.strptime

徘徊边缘 提交于 2019-12-21 18:05:20

问题


I've been working on parsing strings and I have a test case that has been causing problems for me. When parsing a date/time string with strptime, Daylight Savings Time is NOT accounted for. This is a bug as far as I can tell. I can't find any docs on this bug. Here is a test case in the Rails console. This is ruby 1.9.3-p215 and Rails 3.2.2.

1.9.3-p125 :049 >   dt = DateTime.strptime("2012-04-15 10:00 Central Time (US & Canada)", "%Y-%m-%d %H:%M %Z")  
=> Sun, 15 Apr 2012 10:00:00 -0600  
1.9.3-p125 :050 > dt = DateTime.strptime("2012-04-15 10:00 Central Time (US & Canada)", "%Y-%m-%d %H:%M %Z").utc  
=> Sun, 15 Apr 2012 16:00:00 +0000  
1.9.3-p125 :051 > dt = DateTime.strptime("2012-04-15 10:00 Central Time (US & Canada)", "%Y-%m-%d %H:%M %Z").utc.in_time_zone("Central Time (US & Canada)")  
=> Sun, 15 Apr 2012 11:00:00 CDT -05:00  

As you can see, I have to convert to utc and then back to the timezone to get DST to be properly interpreted, but then the time is shifted one hour as well, so it's not what I parsed out of the string. Does someone have a workaround to this bug or a more robust way of parsing a date + time + timezone reliably into a DateTime object where daylight savings time is properly represented? Thank you.

Edit: Ok, I found a workaround, although I'm not sure how robust it is.

Here is an example:

ActiveSupport::TimeZone["Central Time (US & Canada)"].parse "2012-04-15 10:00"  

This parses the date/time string into the correct timezone. I'm not sure how robust the parse method is for handling this so I'd like to see if there is a better workaround, but this is my method so far.


回答1:


This is a frustrating problem. The Rails method you're looking for is Time.zone.parse. First use DateTime.strptime to parse the string, then run it through Time.zone.parse to set the zone. Check out the following console output:

> Time.zone
 => (GMT-06:00) Central Time (US & Canada) 
> input_string = "10/12/12 00:00"
> input_format = "%m/%d/%y %H:%M"
> date_with_wrong_zone = DateTime.strptime(input_string, input_format)
 => Fri, 12 Oct 2012 00:00:00 +0000 
> correct_date = Time.zone.parse(date_with_wrong_zone.strftime('%Y-%m-%d %H:%M:%S'))
 => Fri, 12 Oct 2012 00:00:00 CDT -05:00 

Notice that even though Time.zone's offset is -6 (CST), the end result's offset is -5 (CDT).




回答2:


Ok, here is the best way I've found to handle this so far. I created a utility method in a lib file.

# Returns a DateTime object in the specified timezone
def self.parse_to_date(date_string, num_hours, timezone)
  if timezone.is_a? String
    timezone = ActiveSupport::TimeZone[timezone]
  end

  result = nil
  #Chronic.time_class = timezone # Trying out chronic time zone support - so far it doesn't work
  the_date = Chronic.parse date_string
  if the_date
    # Format the date into something that TimeZone can definitely parse
    date_string = the_date.strftime("%Y-%m-%d")
    result = timezone.parse(date_string) + num_hours.to_f.hours
  end

  result
end

Note that I add hours onto the time manually because Chronic.parse wasn't as robust as I liked in parsing times - it failed when no trailing zeros were added to a time, for example, as in 8:0 instead of 8:00.
I hope this is useful to someone. Parsing date/time/timzone strings into a valid date seems to be a very common thing, but I was unable to find any parsing code that incorporated all three together.



来源:https://stackoverflow.com/questions/10100456/rails-daylight-savings-time-not-accounted-for-when-using-datetime-strptime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!