Есть ли способ изменить временные метки по умолчанию в Rails на Ymd H: i: s (вместо Ymd H: i: su) или заставить laravel игнорировать десятичную часть Ymd H: i: su? - PullRequest
0 голосов
/ 18 октября 2018

У меня есть два приложения, использующих одну и ту же базу данных postgres.Приложение Laravel и приложение рельсов.Текущие данные в БД имеют формат Y-m-d H:i:s, но всякий раз, когда рельсы добавляют записи, формат равен Y-m-d H:i:s.u, который включает миллисекунды.

Это приводит к следующей ошибке на стороне laravel, если дата create_at когда-либо ссылается на laravel InvalidArgumentException Trailing data ...

Модели Laravel могут изменять свой формат даты, поэтому я могу включить егосоответствует Y-m-d H:i:s.u, тогда мне нужно будет обновить все записи, чтобы иметь миллисекунды в дате создания / времени (и любых других временных отметок).К сожалению, когда я задаю формат Y-m-d H:i:s для модели laravel, он не будет игнорировать десятичные дроби.Вот почему я сейчас ищу способы сохранить рельсы по умолчанию в формате Y-m-d H:i:s вместо миллисекунд.Тогда и приложения Rails, и приложения Laravel будут использовать один и тот же формат, и конфликта не будет.

Я знаю, что могу зайти в БД и изменить тип столбца на timestamp (0), который усекает десятичные дроби, но я бы предпочел изменить формат, который сохраняют фреймворки, а не изменить то, что примет БД.

Обе Y-m-d H:i:s и Y-m-d H:i:s.u являются действительными временными метками ... Если бы я мог заставить Rails использовать формат Y-m-d H:i:s или заставить Laravel игнорировать .u при просмотре временных меток, чтобы предотвратить ошибку конечных данных,Я был бы в чистом виде.

Есть ли способ изменить формат по умолчанию, при котором рельсы сохраняют временные метки в БД?

Есть ли способ заставить Larave Carbon игнорировать десятичную часть временной меткив формате Y-m-d H:i:s.u?

Спасибо

Ответы [ 3 ]

0 голосов
/ 18 октября 2018

Решение на стороне Rails

Кажется, что ActiveRecord, используемый в Rails (5.2), автоматически добавляет десятичные секунды до 1 мс при сохранении created_at и updated_at или любых других столбцов меток времени в БД, которые принимаютсекунды, как определено в файле active_record/connection_adapters/abstract/quoting.rb

Обходной путь - это.Добавьте эту строку на верхнем уровне в любой из файлов, которые всегда будут считываться Rails при доступе к модели (например, файл модели ApplicationRecord).

Time::DATE_FORMATS[:db] = '%Y-%m-%d %H:%M:%S.000000000'

module ActiveRecord::ConnectionAdapters::Quoting
  alias_method :quoted_date_orig, :quoted_date if ! self.method_defined?(:quoted_date_orig)

  def quoted_date(*rest, **kwd)
    quoted = quoted_date_orig(*rest, **kwd)
    quoted.sub(/(\.\d*)\.\d{6}$/, '\1')
  end
end

Вы можете подтвердить это из консоли Rails, послесоздание новой записи,

MyModel.last.created_at.nsec  # => 0

или просто прямой доступ к БД для ее просмотра.

Предупреждение

Это изменение касается не только created_at и updated_at, нотакже все остальные столбцы меток времени в БД.Я думаю, что вы все еще можете сохранить значение с точностью до мсек (или нсек) для такого столбца, установив строку в отличие от экземпляра Time для экземпляра модели, например my_model.col_msec_desired = "2018-01-02 03:04:05.678";тогда Time::DATE_FORMATS[:db] не будет использоваться для сохранения записи.

Потенциальное решение на стороне Laravel

Это может быть сложно на момент написания (2018-10-18), ноПохоже, что работа продолжается, согласно очень недавнему сообщению Laracast от cmbertsch01

(Примечание: крупное обновление было сделано через день после исходного сообщения после комментария.)

0 голосов
/ 18 октября 2018

вы можете установить Time :: DATE_FORMATS [: db] в application.rb

Time::DATE_FORMATS[:db] = "Y-m-d H:i:s.u"

выглядит больше на strftime формат

0 голосов
/ 18 октября 2018

В Laravel / PHP вы можете преобразовать DateTime с миллисекундами в миллисекунды без использования следующей функции:

$date = date('Y-m-d H:i:s.u');
echo date('Y-m-d H:i:s', strtotime($date));

В Rails вы можете обновить ваш объект времени перед отправкой его в базу данных, как указано ниже:

time.change(:usec => 0)
...