Я нахожусь в США, и мы обычно форматируем даты как "месяц/день/год". Я пытаюсь убедиться, что мое приложение Rails, использующее Ruby 1.9, принимает этот формат везде и работает так, как это было в Ruby 1.8.
Я знаю, что у многих людей есть эта проблема, поэтому я хотел бы создать окончательное руководство здесь.
В частности:
- '04/01/2011 '- 1 апреля 2011 года, а не 4 января 2011 года.
- '4/1/2011' также является 1 апреля 2011 года - ведущие нули не должны быть необходимы.
Как я могу это сделать?
Вот что я до сих пор.
Контроль даты # to_s поведение
У меня есть эта строка в application.rb
:
# Format our dates like "12/25/2011'
Date::DATE_FORMATS[:default] = '%m/%d/%Y'
Это гарантирует, что если я сделаю следующее:
d = Date.new(2011,4,1)
d.to_s
... Я получаю "04/01/2011", а не "2011-04-01".
Управление строкой # to_date поведение
В настоящее время метод ActiveSupport String#to_date
выглядит следующим образом (источник):
def to_date
return nil if self.blank?
::Date.new(*::Date._parse(self, false).values_at(:year, :mon, :mday))
end
(В случае, если вы этого не сделаете, вторая строка создаст новую дату, пройдя год, месяц и день в этом порядке. То, как она получает значения года, месяца и дня, используется Date._parse
, который анализирует строку и каким-то образом решает, что это за значения, а затем возвращает хэш. .values_at
извлекает значения из этого хеша в порядке Date.new
хочет их.)
Так как я знаю, что обычно буду проходить в строках типа "04/01/2011" или "4/1/2011", я могу исправить это путем monkeypatching его следующим образом:
class String
# Keep a pointer to ActiveSupport String#to_date
alias_method :old_to_date, :to_date
# Redefine it as follows
def to_date
return nil if self.blank?
begin
# Start by assuming the values are in this order, separated by /
month, day, year = self.split('/').map(&:to_i)
::Date.new(year, month, day)
rescue
# If this fails - like for "April 4, 2011" - fall back to original behavior
begin
old_to_date
rescue NoMethodError => e
# Stupid, unhelpful error from the bowels of Ruby date-parsing code
if e.message == "undefined method `<' for nil:NilClass"
raise InvalidDateError.new("#{self} is not a valid date")
else
raise e
end
end
end
end
end
class InvalidDateError < StandardError; end;
Это решение заставляет мои тесты проходить, но это безумие? Я просто пропускаю параметр конфигурации где-нибудь или есть другое, более простое решение?
Существуют ли какие-либо другие случаи синтаксиса даты, которые я не закрываю?