Rails + Postgres:不从连接表中返回列的时区信息

时间:2012-08-22 06:06:02

标签: ruby-on-rails postgresql

活动有很多变化。

我的班次表包含starts_atends_at列,这些列是DATETIME格式。

如果我查询轮班表,starts_atends_at列将返回一个包含时区信息的字符串,并被Rails识别为ActiveSupport::TimeWithZone对象 - 我可以操作它相应

如果我在涉及联接的更复杂查询中包含shifts.starts_atshifts.ends_at列,我似乎会丢失结果集中的时区信息。请考虑以下查询:

SELECT events.id, events.name, events.default_shift_start,
shifts.id AS shift_id, shifts.starts_at, shifts.ends_at, users.id AS user_id,
users.first_name, users.last_name 
FROM "events" 
INNER JOIN "shifts" ON "shifts"."event_id" = "events"."id" 
INNER JOIN "requests" ON "requests"."shift_id" = "shifts"."id" 
INNER JOIN "users" ON "users"."id" = "requests"."user_id" 
WHERE (events.default_shift_start > '2012-08-22 05:55:22.069340' AND requests.status = 'accepted') 
ORDER BY default_shift_start ASC

编辑:我通过以下方式在Rails中调用此查询:

Event.joins(:shifts => { :requests => :user}).where(["events.default_shift_start > ? AND requests.status = ?", Time.now, "accepted"]).select("events.id, events.name, events.default_shift_start, shifts.id AS shift_id, shifts.starts_at, shifts.ends_at, users.id AS user_id, users.first_name, users.last_name").order("default_shift_start ASC")

产地:

+-----+----------+---------------------+---------------------+
| id  | shift_id | starts_at           | ends_at             |
+-----+----------+---------------------+---------------------+
| 17  | 80       | 2012-08-23 00:30:00 | 2012-08-23 07:30:00 |
| 17  | 55       | 2012-08-23 00:30:00 | 2012-08-23 07:30:00 |
+-----+----------+---------------------+---------------------+

问题是JOINed表(shifts)中的列没有返回任何时区数据,导致Rails将它们识别为String数据。数据以UTC格式存储在数据库中。如果我在同一查询中包含datetime表中的events列,则会在结果中包含时区数据。

我一直在搜索文档,试图了解这里发生了什么,但无济于事。

2 个答案:

答案 0 :(得分:2)

我想你应该首先掌握所涉及的数据类型。 PostgreSQL中的“datetime”数据类型实际上是timestamp and there are two variants: with and without time zone。默认值为without

在内部,PostgreSQL始终存储UTC时间戳。时区数据本身保存所有时间戳,无论是否有时区。这些只是输入和输出的装饰器,适用于客户端的时区设置。

查找更多detailed explanation, examples and links at this related answer

答案 1 :(得分:0)

我想如果你把starts_at :: timestamptz放进去,那么你就是好人。