【问题标题】:Linking datetimes of events to their associated location timezone (TimeZone gem, ActiveSupport::TimeWithZone)将事件的日期时间链接到其关联的位置时区(TimeZone gem,ActiveSupport::TimeWithZone)
【发布时间】:2012-08-08 07:20:42
【问题描述】:

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

这个帖子是为了分享我的问题,以及什么有效,部分原因是在我看来,很多时候日期时间记录应该与其所在位置的本地时间相关联,而且很多时候应用程序的行为奇怪的是,关于时区的变化,我认为这是因为他们不这样做。所以这里是如何做到这一点的。

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

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

所以,没关系——数据库以 UTC 存储,我必须在每个方向上进行转换。

怎么样? (见下文。)

【问题讨论】:

    标签: ruby-on-rails-3 datetime timezone location geocoding


    【解决方案1】:

    用户在活动地点的适当本地时间输入日期时间(年、月、日、小时、分钟、秒)。要将其保存为数据库中正确的 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 
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-15
      相关资源
      最近更新 更多