【问题标题】:Sinatra/Ruby time zone troubles between development & production开发和生产之间的 Sinatra/Ruby 时区问题
【发布时间】:2012-10-30 09:24:54
【问题描述】:

我的 Sinatra 应用正在创建一个简单的对象并将其持久化到 Postgres:

post '/' do
  event = Event.new(params)
  event.created_at = Time.now.utc
  event.date = next_date(params[:dayofweek], params[:time]) if params[:dayofweek] && params[:time]

  if event.save
    status 201
    event.to_json
  else
    json_status 400, event.errors.to_hash
  end

def next_date(dayofweek, hour)
  ...
  # some calculations that effectively culminate in the final line below
  ...
  my_time = Time.utc(2012, 11, 9, 12, 0, 0)   ## => 2012-11-09 12:00:00 UTC  
end

对象保存成功。但是当我从development 环境中检索对象时,我得到(json):

{ ..., "date":"2012-11-23T20:00:00-08:00" }   #notice the PST offset of -08:00. 

我期待 UTC 时区 +00:00。出于某种原因,我在 PST 中的开发工作站在保存到 Postgres 时会考虑自己的时区……至少它看起来在做什么?!?

将相同的代码发送到生产服务器 (Heroku) 存储相同的数据,并具有适当的偏移量 +00:00

如何让我的开发工作站像生产工作站一样工作?或者,我应该如何在 Sinatra 中创建正确的 UTC Date 对象?

【问题讨论】:

  • @joelparkerhenderson 下面给出了很好的答案,但不要忘记检查您用来连接数据库的库(我假设您使用的是 AR 或 Sequel 或其他东西)这也会产生影响。
  • 谢谢,您的评论让我找到了可能的解决方案,尽管我还没有测试过。我正在使用 DataMapper,在他们的网站上四处挖掘后,我发现"time properties will always be stored and retrieved in the timezone the datastore is set to"link to a gem 将强制一个特定区域。 如果你想把它变成一个答案,我会把复选标记扔给你。
  • 所以,在尝试了这颗宝石之后,它首先是 2 岁!?!并且似乎不起作用...它将日期设置为某种非 ISO 格式 "2012-11-13 10:00:00 -0800" 并将 UTC 偏移量保持为 PST (-08:00)。所以,我不知道该怎么办!?!这很奇怪,因为我一直认为所有数据通常都应该以 UTC 格式保存。但是 DataMapper 故意让这变得困难。 这是我第一个使用 Sinatra 的应用程序。我一定做错了什么?!?我应该切换到 ActiveRecord 吗?
  • 我会等到它修好,然后我觉得我已经做了一些值得勾选的事情:) 试试这两件事 1) 在 Postgres 中,SET timezone TO 'UTC'; select current_setting('timezone'); 2) 将 TZ 环境变量设置为 ' UTC',尝试TZ=UTC ruby my_sinatra_app.rb 看看是否有效,如果有效,则在 rackup 文件或 Sinatra 配置块中设置 env var。
  • 是的,从 DataMapper 切换到 ActiveRecord。

标签: ruby datetime timezone sinatra datamapper


【解决方案1】:

首先验证您的数据是否成功往返:

event.created_at = Time.now.utc
event.date = ...whatever...
tmp_created_at = event.created_at
tmp_date = event.date
event.save
event.reload!
tmp_created_at == event.created_at or raise "created_at failed"
tmp_date == event.date_at or raise "date failed"

其次,验证 JSON 是否准确。

  • 将 JSON 时间字符串与预期时间进行比较
  • JSON 时间字符串为 -08:00
  • JSON 字符串的实际时间是否相同?
  • 例如,如果您预计 10:00Z,JSON 是显示 02:00-08:00(即相同的实际时间)还是 10:00-08:00(不同的实际时间 - 这是八几小时后)。

如果数据往返有效,并且 JSON 的实际时间相同,则查看您用于打印字符串的任何 JSON 库。寻找像“iso8601”这样的方法,以标准 UTC 格式打印时间。

另外,知道 Postgres 默认保存没有时区的时间戳可能会有所帮助。

“SQL 标准要求仅写入时间戳等同于不带时区的时间戳,并且 PostgreSQL 尊重这种行为。(7.3 之前的版本将其视为带时区的时间戳。) timestamptz 被接受为带时间的时间戳的缩写zone;这是一个 PostgreSQL 扩展。"

您可以通过描述表格来看到这一点,它可能看起来像这样:

# \d events
Table "public.events"
Column     |            Type             |      Modifiers    
-----------+-----------------------------+-----------------------------------
id         | integer                     | not null default  
name       | character varying(255)      | 
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
date       | timestamp with time zone    | not null

更多信息基于 OP 的反馈...

OP 说:我正在使用 DataMapper,在他们的网站上四处挖掘后,我发现“时间属性将始终在数据存储设置的时区中存储和检索”,以及指向将强制执行特定操作的 gem 的链接区域。

由于往返显示有问题,请尝试使用当前版本的连接库,例如当前的 DataMapper,并尝试任何类似库的当前版本,例如ActiveRecord(撰写本文时版本为 3.2.8)。

【讨论】:

  • 好消息!非常感激。往返示例代码帮助我证明它确实失败了,但仍然没有告诉我原因。事实证明,这似乎是 DataMapper 的“功能”(请参阅​​对 OP 的评论)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 2010-11-27
  • 2013-02-23
  • 2013-12-14
  • 2011-10-09
  • 2011-12-13
相关资源
最近更新 更多