0

我为此苦苦挣扎了一天半,最后才终于走到了一起,部分原因是我从根本上误解了一些事情,因为我对事情应该如何运作的假设,所以我得到的结果似乎完全不合理和令人困惑我开始认为图书馆里的东西一定被严重破坏了。他们不是。

这个线程是为了分享我的问题,以及什么有效,部分原因是在我看来,很多时候日期时间记录应该与其位置的本地时间相关联,而且很多时候应用程序在时区更改方面表现异常我认为这是因为他们不这样做。所以这里是如何做到这一点。

简单的部分是使用 TimeZone gem 来获取位置的时区(我已经有了使用 GMaps4Rails gem 的纬度/经度),如下所述: Ruby gem for find timezone of location

最初,我希望每个日期时间都可以有一个固有的和持久的时区,即使在从数据库中保存和检索之后,因为我们只关心每个事件的本地时区。对于在非本地区域中需要日期时间的不寻常和罕见的情况,我可以转换。但我猜这不存在,因为 MySQL 似乎没有带有日期时间的时区概念,并且只是将所有内容存储为普通的日期和时间。

所以,这很好——数据库存储在 UTC 中,我必须在每个方向上进行转换。

如何?(见下文。)

4

1 回答 1

0

用户在事件地点的适当本地时间输入日期时间(年、月、日、小时、分钟、秒)。要将其保存为数据库中正确的 UTC 时间,并在稍后检索它并将其与正确的时区一起使用,以下是配方:

  1. 您必须首先设置Time.zone = timezone-- 其中 timezone 是一个命名的时区字符串,例如"America/Toronto"(GeoKit/TimeZone 样式)或"Eastern Time (US & Canada)"(Rails 3 样式):

    1.9.3p200 :001 > Time.zone = "America/Toronto"
     => "America/Toronto"
    

    请注意,在 GeoKit/TimeZone 样式和 Rails 3 样式之间进行映射并非易事。对此有一些支持,但 GeoKit 返回的许多映射不在 Rails 映射中,所以我坚持使用 GeoKit/TimeZone 名称,因为它们似乎工作得很好,而且我不需要用户可选择时区,因为我正在为使用这些位置的用户自动处理所有这些。

  2. 现在您可以使用 解析和保存您的日期时间变量ActiveSupport::TimeWithZone,它将使用Time.zone参数正确编码:

    1.9.3p200 :002 > t = Time.zone.local( 2012, 8, 1, 12, 0, 0 )
     => Wed, 01 Aug 2012 12:00:00 EDT -04:00 
    

    即在我的情况下,对于我Event的带有实例的模型event

    event.start = Time.zone.local( year, month, day, hour, min, sec )
    event.save
    

    当数据保存到数据库时,它是 UTC: 2012-08-01 16:00:00.000000

    (下面通过调用模拟t.utc

    1.9.3p200 :003 > t = t.utc
     => 2012-08-01 16:00:00 UTC
    
    1.9.3p200 :004 > t.zone
     => "UTC" 
    
  3. 现在,当您从数据库中读回它时,您需要再次使用TimeWithZone支持来告诉 DateTime 它所在的时区。

    请注意,该in_time_zone函数不会更改基础 datetime 变量的时区:

    1.9.3p200 :005 > t.in_time_zone( "America/Toronto" )
     => Wed, 01 Aug 2012 12:00:00 EDT -04:00 
    
    1.9.3p200 :006 > t
     => 2012-08-01 16:00:00 UTC 
    
    1.9.3p200 :007 > t.zone
     => "UTC" 
    

    所以你真的需要将函数输出分配回你的 datetime 变量:

    1.9.3p200 :008 > t = t.in_time_zone( "America/Toronto" )
     => Wed, 01 Aug 2012 12:00:00 EDT -04:00 
    
    1.9.3p200 :009 > t
     => Wed, 01 Aug 2012 12:00:00 EDT -04:00 
    
    1.9.3p200 :010 > t.zone
     => "EDT" 
    
  4. 最后,一个警告——不要使用t.time!它的输出完全无用且不合理,时间和时区不同步:

    1.9.3p200 :011 > t.time
     => 2012-08-01 12:00:00 UTC 
    
于 2012-08-11T00:58:40.870 回答