无法保存时间戳 - postgresql

时间:2012-11-11 11:50:44

标签: ruby-on-rails ruby postgresql

我有以下代码段:

class Foo    
  include DataMapper::Resource
  property :id, Serial
  property :timestamp, DateTime
 end

我只想将当前时间转换为ms:

 class Time
   def to_ms
     (self.to_f * 1000.0).to_i
   end
 end

 def current_time
   time = Time.now
   return time.to_ms
  end

  time = current_time # => 1352633569151

但是当我要使用上面的时间戳保存Foo时,它无法保存到数据库中,而且我没有收到任何错误消息。

foo = Foo.new
foo.timestamp = time
foo.save

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

您使用的是:datetime属性的正确格式吗?

应该是:

DateTime.now.to_s
=> "2012-11-11T14:04:02+02:00"

或“本机”DateTime对象,没有任何转换。

DataMapper将根据使用的适配器将其转换为相应的值。

另外,保存项目时会引发异常:

DataMapper::Model.raise_on_save_failure = true 

这是一个全局设置,即所有模型都会引发异常。

只使某些模型表现得像这样:

YourModel.raise_on_save_failure = true

http://datamapper.org/docs/create_and_destroy.html

请参阅“保存失败时引发异常”一章

顺便说一句,要在保存项目之前查看项目有什么问题,请使用item.valid?item.errors

foo = Foo.new
foo.timestamp = time
if foo.valid?
  foo.save
else
  p foo.errors
end

我复制了你的代码并得到了以下错误:

@errors={:timestamp=>["Timestamp must be of type DateTime"]}

请参阅live demo here

答案 1 :(得分:2)

PostgreSQL数据类型为timestamp or timestamp with time zone。但这与你正在做的事情相矛盾。您获取纪元值并乘以1000.您必须将其保存为integer或某些numeric type

More about the handling of timestamps in Postgres in this related answer.

我会将值保存为timestamp with time zone(不是乘法)。如果需要,你总是可以从中提取ms。

如果您需要将Unix纪元值转换回时间戳,请使用:

SELECT to_timestamp(1352633569.151);
--> timestamptz 2012-11-11 12:32:49.151+01

只需保存“现在”

如果你实际上想要保存“现在”,即当前时间点,那么让Postgres为你做。只需确保数据库服务器具有可靠的本地时间 - 安装ntp。这通常更可靠,准确和简单。

将时间戳列的DEFAULT设置为now()CURRENT_TIMESTAMP
如果您想要timestamp而不是timestamptz,您仍然可以使用now(),根据服务器时区设置将其转换为“本地”时间。或者,为了获得给定时区的时间:

now() AT ZIME ZONE 'Europe/Vienna'  -- your time zone here

或者,在您的特定情况下,因为您似乎只需要三个小数位:now()::timestamp(3)CURRENT_TIMESTAMP(3)CURRENT_TIMESTAMP(3) AT ZIME ZONE 'Europe/Vienna'
或者,如果您将列的类型定义为timestamp(3),则所有时间戳值都会强制转换为类型并自动舍入为3个小数位数。

所以这就是你所需要的:

CREATE TABLE tbl (
   -- other columns
  ,ts_column timestamp(3) DEFAULT now()
);

该值会自动设置在 INSERT 上,您甚至不必提及该列。
如果您想要更新 ON UPDATE ,请添加TRIGGER,如下所示:

触发功能:

CREATE OR REPLACE FUNCTION trg_up_ts()
  RETURNS trigger AS
$BODY$
BEGIN
   NEW.ts_column := now();
   RETURN NEW;
END
$BODY$ LANGUAGE plpgsql VOLATILE

触发:

CREATE TRIGGER log_up_ts
BEFORE UPDATE ON tbl
FOR EACH ROW EXECUTE PROCEDURE trg_up_ts();

现在,所有内容自动生效 如果那不是你所追求的,@slivu's answer似乎很好地涵盖了Ruby方面。

答案 2 :(得分:0)

我不熟悉PostgreSQL,但为什么要将Fixnum(time)分配给timestamp(这是一个DateTime)?在生成SQL之前,您的模型必须无法将time转换为正确的DateTime值。

试试foo.save!。我很确定你会看到一个错误,或者从PostgreSQL报告,说1352633569151不是表列的有效值,或者你的模型会说它无法将1352633569151解析为有效的DateTime。

foo.timestamp = Time.nowfoo.timestamp = '2012-11-11 00:00:00'是可行的。