【问题标题】:How to store "DateTime.now" as the current DateTime object如何将“DateTime.now”存储为当前的 DateTime 对象
【发布时间】:2020-07-25 15:02:34
【问题描述】:

我的环境是:

  • Ruby 2.6.3p62(2019-04-16 修订版 67580)[x86_64-darwin18]
  • Rails 6.0.2.1
  • MacOS X Mojave
  • psql
  • Puma 版本 4.3.3 (Ruby 2.6.3-p62)

出于某种原因,Rails 在我的数据库中将DateTime.now 保存为未来 7 小时:

2.6.3 :002 > DateTime.now
 => Sun, 12 Apr 2020 20:52:00 -0700
2.6.3 :003 > v.last_prompting = DateTime.now
 => Sun, 12 Apr 2020 20:52:05 -0700
2.6.3 :004 > v.save
   (0.1ms)  begin transaction
  Volunteer Update (0.3ms)  UPDATE "volunteers" SET "updated_at" = ?, "last_prompting" = ? WHERE "volunteers"."id" = ?  [["updated_at", "2020-04-13 03:52:10.964288"], ["last_prompting", "2020-04-13 03:52:05.779767"], ["id", 1]]
   (1.1ms)  commit transaction
 => true
2.6.3 :005 > v.last_prompting
 => Sun, 12 Apr 2020 20:52:05 PDT -07:00

看看last_promptingupdated_at - 都在 4 月 13 日,今天是 4 月 12 日。

但是当我检查控制台中的时间时,它做了正确的事情:

2.6.3 :005 > v.last_prompting
 => Sun, 12 Apr 2020 20:52:05 PDT -07:00
2.6.3 :006 > v.last_prompting.future?
 => false
2.6.3 :007 > v.last_prompting.past?
 => true

我正在尝试编写一个方法来表达last_prompting 是多久以前的:

def prompting_age
    return "never" if self.last_prompting == nil

    if self.last_prompting.between?(Time.now - 720.minutes, Time.now - 10.years)
      ">12 hrs"
    elsif self.last_prompting.between?(Time.now - 240.minutes, Time.now - 719.minutes)
      ">4 hrs"
    elsif self.last_prompting.between?(Time.now - 61.minutes, Time.now - 239.minutes)
      ">1 hr"
    elsif self.last_prompting.between?(Time.now, Time.now - 60.minutes)
      "<1 hr"
    else
      "weird"
    end
end

每次我测试这个方法时,它都会返回“奇怪”。我认为这是因为 Rails 给出了未来的日期,但是当我通过 Puma 运行应用程序时它不会在控制台中这样做。

【问题讨论】:

  • 我们无法确定问题出在哪里,因为您没有告诉我们有关您的数据库架构的任何信息,但它闻起来像是时区不匹配。您的控制台知道您的计算机所在的时区,但数据库没有任何线索,可能正在使用 UTC。这可能导致这种不匹配。您可以告诉数据库要使用哪个时区,或者,可能更聪明的是,在存储之前将 DateTime 和 Time 值转换为 UTC。另外,您使用的是psql 还是PostgreSQL? psql 是 CLI 客户端,PostgreSQL 是 DBM;它们是不同的,不要混淆。
  • Time.zone.now.in_time_zone('Etc/UTC') 会解决它。

标签: ruby-on-rails ruby postgresql datetime


【解决方案1】:

当使用between? 时,min 参数必须在max 之前出现。你基本上只需要切换属性顺序。

使用通用 Ruby 习语的版本如下所示:

def prompting_age
  return "never" unless last_prompting

  if last_prompting.between?(10.years.ago, 12.hours.ago)
    ">12 hrs"
  elsif last_prompting.between?(12.hours.ago, 4.hours.ago)
    ">4 hrs"
  elsif last_prompting.between?(239.minutes.ago, 61.minutes.ago)
    ">1 hr"
  elsif last_prompting.between?(60.minutes.ago, Time.current)
    "<1 hr"
  else
    "weird"
  end
end

变化:

  • 您的代码中不需要self
  • 没有针对== nil 的显式检查,因为nil 已经错误地存在于Ruby 中
  • Time.now - 720.minutes 更改为720.minutes.ago,这样更易​​于阅读、更短且尊重时区信息。并使用Time.current 而不是Time.now 来尊重时区信息。

此外,您在比较中遗漏了一些时间点,例如,一个条件达到60.minutes,但下一个条件从61.minutes.ago 开始。这意味着您将错过记录,例如 60 分 10 秒前的提示。

为了解决这个问题,我会将代码改写成这样:

def prompting_age
  return "never" unless last_prompting

  if last_prompting.before?(12.hours.ago)
    ">12 hrs"
  elsif last_prompting.before?(4.hours.ago)
    ">4 hrs"
  elsif last_prompting.before?(60.minutes.ago)
    ">1 hr"
  elsif last_prompting.before?(Time.current)
    "<1 hr"
  else
    "weird"
  end
end

请注意,最后一个版本的行为略有改变。对于 10 多年前提示的记录,它不会返回“奇怪”,并且与您的版本相差一秒钟。两者都可能没问题...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 2017-07-25
    • 1970-01-01
    • 2013-02-17
    • 2021-04-04
    • 1970-01-01
    • 2013-03-15
    相关资源
    最近更新 更多