ruby 时间戳无法另存为历元编号

h22fl7wq  于 2023-04-20  发布在  Ruby
关注(0)|答案(3)|浏览(124)

我有下面的代码片段:

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

你知道吗?

esbemjvw

esbemjvw1#

你是否使用正确的格式为您的: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

ql3eal8s

ql3eal8s2#

PostgreSQL的数据类型应该是timestamp or timestamptz。但这与你正在做的事情相矛盾。你取epoch值并乘以1000。你必须将其保存为bigint或一些numeric type
基础知识:

  • 在Rails和PostgreSQL中完全忽略时区

我会将值保存为timestamptz。(没有乘法。)如果需要,您可以随时提取ms。
如果需要将Unix epoch值转换回时间戳,请用途:

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

保存“现在”即可

如果你真的想保存“现在”,也就是当前的时间点,那么就让Postgres来帮你保存吧。只要确保数据库服务器有一个可靠的本地时间即可。(可以在服务器上安装ntp。)这样通常更可靠,更准确,更简单。

将timestamp列的DEFAULT设置为now()CURRENT_TIMESTAMP
如果你想要timestamp而不是timestamptz,你仍然可以使用now(),它会根据服务器的时区设置转换为“本地”时间-实际上与LOCALTIMESTAMP相同。或者,获取给定时区的时间:

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

或者,在您的特定情况下,因为您似乎只想要三个小数位:now()::timestamp(3),或CURRENT_TIMESTAMP(3),或CURRENT_TIMESTAMP(3) AT ZIME ZONE 'Europe/Vienna',或date_trunc('ms', LOCALTIMESTAMP)。后者 * 截断 *,而其他 * 舍入 *。通常,您希望截断。请参阅:

  • 从时间戳中丢弃毫秒部分

或者,如果将列的类型定义为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
  LANGUAGE plpgsql AS
$func$
BEGIN
   NEW.ts_column := now();
   RETURN NEW;
END
$func$

触发器:

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

在Postgres 10或更早版本中,使用关键字PROCEDURE而不是FUNCTION。请参阅:

现在,一切都自动工作。

nkcskrwz

nkcskrwz3#

我对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'是可行的。

相关问题