47

我在 Debian 上使用 Rails 3.2 和 ruby​​ 1.9.3。我有一个应用程序,它通过 HTML 表单以字符串的形式收集日期、时间和时区。像这样的东西:

start_date: "04-15-2010",
start_time: "10:00:00",
timezone: "Central Time (US & Canada)"

我想要做的是将这 3 个元素解析为一个日期,该日期作为 UTC 保存到我的数据库中,在这种情况下,一旦它处于 UTC 时区,它将增加 7 小时的开始时间。因此,一旦它作为 UTC 在数据库中存储的时间将是 17:00,而不是接收到的中央时间。

我尝试过这样的事情来解析日期:

ActiveSupport::TimeZone[timezone].at DateTime.strptime("{ 2012-04-09 20:00:00 }", "{ %Y-%m-%d %H:%M:%S }").to_i

但是,我无法使用 %Z 将时区合并到结果时间中。它要么不解析,要么时间被解释为 UTC 而不是中央时间。所以我的问题是,如何在不更改存储的实际日期/时间值的情况下将日期字符串强制转换为某个时区。我希望能够将字符串解析为包含正确时区的日期/时间对象,以便将来的时区转换是准确的。我已经看遍了,找不到办法做到这一点。这很奇怪,因为这似乎与从 HTML 表单输入的日期一样常见。感谢您的任何帮助。

4

7 回答 7

121

试试这个:

zone = "Central Time (US & Canada)"  

ActiveSupport::TimeZone[zone].parse("2013-04-03 17:47:00")
于 2013-04-03T09:53:54.687 回答
56

使用String#in_time_zone(Rails 4+)

我个人更喜欢使用String#in_time_zone

>> '22.09.1986 10:30'.in_time_zone('Central Time (US & Canada)')
# => Mon, 22 Sep 1986 10:30:00 CDT -05:00

这会将字符串中的日期和时间解析为提供的时区。

于 2015-08-10T19:56:47.123 回答
24

%Z是指定时区名称的正确方法。您是否尝试过以下操作?

date_and_time = '%m-%d-%Y %H:%M:%S %Z'
DateTime.strptime("04-15-2010 10:00:00 Central Time (US & Canada)",date_and_time)
于 2012-04-10T16:20:01.093 回答
2

这是我想出的方法。不是最漂亮的,但它有效。允许使用指定的格式解析字符串,然后将其转换为我知道Time.zone.parse需要的格式。

class ActiveSupport::TimeZone
  def strptime(time, format='%m/%d/%Y')
    formatted = Time.strptime(time, format).strftime('%Y-%m-%d %T')
    parse(formatted)
  end
end

然后你可以做一些类似另一个问题中提到的事情,但使用指定的格式:

zone = "Central Time (US & Canada)"  
ActiveSupport::TimeZone[zone].strptime('2013-04-03', '%Y-%m-%d')

或者,如果您已经设置了时区:

Time.zone = "Central Time (US & Canada)" 
Time.zone.strptime('01/13/2006')

我使用了默认格式,%m/%d/%Y因为这是我的用户输入的大部分时间。您可以根据自己的需要自定义它,或者使用默认格式DateTime,相信是 iso8601 ( %FT%T%z)

于 2016-03-22T01:14:36.687 回答
1

我终于找到了肮脏但明确的方法来做到这一点。

首先,使用普通的 Ruby Time.strptime 解析字符串,如下所示:

time = Time.strptime('12 : 00 : PM', '%I : %M : %p')

这样你就得到了解析的时间,但还没有在正确的时区。为了解决这个问题,让我们将时间转换为字符串形式并使用标准的 ActiveSupport::TimeZone#parse 解析它

Time.zone.parse(time.to_s)

结果是 ActiveSupport::TimeWithZone 将我们的时间解析为正确的时区。

我们之所以必须这样做,是因为 ActiveSupport::TimeZone 和 ActiveSupport::TimeWithZone 都不支持 strptime 方法。因此,我们必须使用没有时区信息的核心 Ruby strptime 解析时间,将其转换为 ActiveSupport 对象中可接受的格式,然后再次解析它。

于 2016-05-09T11:42:05.470 回答
-1

要让 DateTime 获取日期字符串并附加 UTC 以外的时区而不更改日期字符串的值,请使用它,它很简单,不会在闰日中断:)

xx = DateTime.strptime("9/1/15 #{object.time_zone}", "%m/%d/%Y %Z")
于 2015-11-13T22:33:38.917 回答
-1

转换 UTC 中的特定日期格式。

ActiveSupport::TimeZone['UTC'].parse(Time.strptime('01/24/2019T16:10:16', "%m/%d/%YT%H:%M:%S").asctime)
于 2019-02-13T10:46:11.773 回答