比较来自 SQL 请求和 Time.now.utc 的日期时间



我有一个jsonb字段,我在其中存储令牌到期日期,如下所示:

user.token = {token_expires: Time.now.utc}
user.save

当我这样做时

user.token['token_expires']
=> "2018-09-23T18:21:58.010Z"

结果是2018-09-23T18:21:58.010Z

如果我在控制台中检查当前日期时间

Time.now.utc
=> 2018-09-23 19:06:20 UTC

结果是2018-09-23 19:06:20 UTC

现在的问题是当我尝试运行以下请求时:

User.where("""users.token ->> 'token_expires' <= :current_time""",
current_time: Time.now.utc).pluck(:id)
=> []  # returns an empty array/result

所以令牌到期日期是 2018-09-23T18:21:58.010Z,当前日期时间为 2018-09-23 19:06:20UTC但在请求中,当我尝试获取token_expires < Time.now.utc的用户时,我一无所获! 我期待的是获得我第一次创建的用户

我会在这里回答我的问题,希望有人觉得有用

每个人都需要了解的是,日期或日期时间作为字符串存储在json/jsonb 字段中,通常我的代码发生了什么

user.token = {token_expires: Time.now.utc}
user.save

是 Rails 隐式地将Time.now.utc转换为iso8601,它被存储为字符串,这就是为什么当我这样做(在我的控制台中(时

的原因
user.token['token_expires']

我得到"2018-09-23T18:21:58.010Z">,这是我以前的 Time.now.utc 的 iso8601 格式

我不打算解释为什么 Rails 会进行这种转换,但据我了解,建议使用 ISO-8601 格式在数据库中存储日期/日期时间,特别是对于 json/jsonb 字段,因为它可以轻松处理日期或使用 API 时

您可以存储 ISO-8601 以外的其他格式吗?是的,你可以,这取决于您的需求,例如,我能够通过在我的代码中传递字符串而不是像这样的日期时间来阻止 Rails 为我进行隐式转换:

user.token = {token_expires: Time.now.utc.to_s}
user.save

存储的日期时间(字符串(将如下所示:2018-09-23 18:21:58 UTC

您可能希望将日期存储为 unix 时间,这取决于您!

所以回到我的问题和不返回任何内容的查询,我的查询如下所示:

User.where("""users.token ->> 'token_expires' <= :current_time""",
current_time: Time.now.utc).pluck(:id)

在sql查询中,我与之比较的Time.now.utc(current_time(变成了这样的2018-09-23 22:21:18.952113,而数据库中的值(jsonb字段(具有不同的格式(iso8601(,这就是我一无所获的原因。

所以为了解决这个问题,我必须通过使用Time.now.utc.to_s显式转换来将当前时间(Time.now.utc(存储为字符串.to_s并防止 Rails 将其转换为 iso...

第二种解决方案是在 SQL 查询中将 iso 日期时间转换为时间戳格式,如下所示:

User.where("""(users.token ->> 'token_expires')::timestamp <= :current_time""",
current_time: Time.now.utc).pluck(:id)

以下是帮助我得出此结论的其他相关问题:

当我想按日期过滤时,ISO8601 PostgreSQL jsonb 的最佳日期格式吗?

JSONb 日期:内部实际日期?

在 Ruby 中将 UTC 时间戳转换为 ISO 8601

最新更新