сравнивая дату и время из sql запроса и Time.now.utc - PullRequest
0 голосов
/ 23 сентября 2018

У меня есть поле 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:20 UTC но в запросе, когда я пытаюсь получить пользователей с token_expires < Time.now.utc, я ничего не получил!я ожидаю, что получу пользователя, которого я создал в первый раз

1 Ответ

0 голосов
/ 24 сентября 2018

Я отвечу на мой вопрос здесь, надеюсь, кто-то найдет его полезным

Все должны понимать, что дата или дата и время хранятся в поле json / jsonb как STRING , и вообще то, что случилось с моим кодом

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

, заключается в том, что Rails неявно конвертирует Time.now.utc в iso8601 , которые сохраняются в виде строки, и этопричина, почему, когда я делаю (в моей консоли)

user.token['token_expires']

, я получаю "2018-09-23T18: 21: 58.010Z" , который является форматом iso8601 моего предыдущего Time.now.utc

Не буду объяснять, почему Rails делает это преобразование, но насколько я понял, рекомендуется использовать формат ISO-8601 для хранения даты / даты и времени в базе данных, особенно для полей json / jsonbПотому что это облегчает работу с датой или при работе с API

Можете ли вы хранить другой формат, кроме ISO-8601? Да, вы можете , это зависит от ваших потребностей, например, я смог предотвратить Rails от неявного преобразования для меня, передав строку в моем коде вместо datetime, например:

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-запросе Время.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 ...

Второе решение - конвертироватьформат iso datetime to timestamp в запросе SQL выглядит следующим образом:

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

Вот и другие связанные вопросы, которые помогли мне прийти к такому выводу:

Является ли ISO8601 лучшим форматом даты для PostgreSQL jsonb, когда я хочу фильтровать по дате?

Даты JSONb: фактические даты внутри?

Преобразование метки времени UTC в ISO 8601 в рубине

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...