Rails3/jQuery UI Datepicker - месяц и день отменены при сохранении

(Моя проблема почти такая же, как описанная в этом вопросе, только этот ответ не работает в моем случае.)


Я использую jQuery UI Datepicker в приложении Rails с db Postgres. Реализация по умолчанию использует формат даты мм/дд/гг, чтобы отобразить выбранную дату, и именно этого я хочу. Однако, после сохранения записи в базе данных, месяц и день меняются на противоположные - тогда она отображается как yy-dd-mm. Таким образом, выбор 3/11/2012 пытается сэкономить 3 ноября вместо 11 марта, а дата типа 3/31/2012 вообще не сохраняется, потому что ее не существует.

Я пропустил еще 3 различных способа, чтобы исправить это:

1) Первая попытка состояла в том, чтобы переформатировать текстовое поле, чтобы дисплей выглядел так, как я хотел:

<%= f.text_field :foo, :value => (@model.foo.blank? ? '' : @model.foo.strftime('%m/%d/%Y')), class: "datepicker" %>

Это отобразилось 03/31/2012 правильно, но при сохранении было отменено.

2) Итак, в следующий раз я попытался изменить способ по умолчанию, в котором хранятся даты, и подумал, что проблема будет решена. Как описано в ответе на этот вопрос, я добавил следующее в config/locales/en.yml:

# config/locales/en.yml
en:
  date:
    formats:
      default: "%m/%d/%Y"

Это не имело никакого значения. Затем я нашел этот вопрос и попытался создать config/initializers/date_formats.rb следующие строки:

Date::DATE_FORMATS[:default]="%m/%d/%Y"
Time::DATE_FORMATS[:default]="%m/%d/%Y %H:%M"

То же, что и выше, без разницы.

3) После игры с множеством комбинаций одна вещь, которую я обнаружил, что работа DID указывала формат yyyy-mm-dd в моем обращении к плагину datepicker - это противоположность того, что я хотел, но, по крайней мере, даты могут быть успешно сохранены. Поэтому вызов datepicker выглядит следующим образом:

$( ".datepicker" ).datepicker({ dateFormat: 'yy-mm-dd' });

Выбор 31 марта из календаря заполняет поле 2012-03-31 и по-прежнему отображается как 2012-03-31 после сохранения.

Но как я могу заставить datepicker работать с форматом mm/dd/yy? Я не могу себе представить, что это сложно сделать, но чего я не хватает? Должен ли я что-то делать с тем, как даты хранятся в Postgres? (Они указаны как дата, а не дата и время.)

Ответы

Ответ 1

Хорошо, это зависит от того, как вы храните данные в своей базе данных. Если вы используете SQL-запросы RAW, вы можете использовать to_date('31 Mar 2012', 'DD Mon YYYY') в своем запросе на вставку.

Postgres 'to_date ссылка

Теперь, на вашей стороне клиента, в jquery date picker вы можете использовать

$.datepicker.formatDate('dd-M-yy', Yourdate);

Я использовал DD Mon YYYY, потому что это кажется яснее. Вы можете использовать формат mm/dd/yy или другие форматы, основанные на потребностях. В таких случаях используйте формат в функции postgre to_date

Просьба отметить, что я не тестировал выше код. Оставьте комментарии, если есть какие-либо проблемы или вы столкнулись с какими-либо проблемами.

Edit:

Вы можете использовать Date.parse('2011-06-18') в вашем представлении рельсов, прежде чем вставлять данные в базу данных и установить formatDate в 'yy-mm-dd' в datepicker.

Ответ 2

Если вы хотите изменить формат даты по умолчанию для своего кластера баз данных, вы также можете установить DateStyle GUC в postgresql.conf и перезагрузить:

datestyle = 'iso, mdy'

(что должно быть по умолчанию в любом случае.)

Обратите внимание, что это не влияет на то, как даты отображаются в вашем приложении. Как PostgreSQL интерпретирует неоднозначный ввод и некоторые параметры вывода Postgres.


Если вы установите параметр datestyle в psql в (очевидно) другом соединении, это ничего не доказывает. Приложение может устанавливать другой datestyle в связи с локальными настройками. Вам нужно будет проверить настройку внутри вашего фактического соединения (не из psql).

Если ваша настройка datestyle 'iso, mdy', тогда она должна работать так, как вы хотите: словарные литеры интерпретируются месяцем раньше. Рассмотрим эту демонстрацию (используя PostgreSQL 9.1):

db=# set datestyle = 'ISO, MDY';
SET
db=# select '1.12.2012'::date;
    date
------------
 2012-01-12
(1 row)

db=# set datestyle = 'ISO, DMY';
SET
db=# select '1.12.2012'::date;
    date
------------
 2012-12-01
(1 row)

Акцент на мой.

Чтобы узнать, какие параметры действительно установлены вашим приложением, вы можете установить

log_statement = all

в postgresql.conf и перезагрузите. Затем запустите приложение и сохраните дату. Каждая команда будет регистрироваться. Не забудьте reset и перезагрузите его (или ваши файлы журналов могут увеличиться):

log_statement = none

Затем проверьте свои файлы журналов db, что ваше приложение действительно отправлено в базу данных.


Вы также можете быть заинтересованы в команде to_date(), которая позволяет вводить литералы даты в любом формате, который вам нравится. Но вам это не нужно.

Ответ 3

Я столкнулся с теми же проблемами, что и исходный плакат. Поскольку мне приходится сравнивать даты/время друг с другом, я не хотел менять поля БД на строки, потому что это потребует дополнительного кода и конверсий позже.

В моей модели я использовал before_save и attr_accessor следующим образом:

before_save    :format_date
attr_accessor  :unformatted_date

def format_date
  self.inquiry_date = Date.strptime(self.unformatted_date, "%m/%d/%Y").to_time(:utc)
end

Строка в моем представлении выглядит следующим образом:

f.text_field  :unformatted_date, :value => (@foo.inquiry_date.blank? ? '' : @foo.inquiry_date.strftime('%m/%d/%Y)), :id => 'datepicker'