Я живу в США, и мы обычно форматируем даты как месяц/день/год. Я пытаюсь убедиться, что мое приложение Rails, использующее Ruby 1.9, везде принимает этот формат и работает так же, как в Ruby 1.8.
Я знаю, что у многих людей есть эта проблема, поэтому я хотел бы создать подробное руководство здесь.
Конкретно:
- «01.04.2011» — это 1 апреля 2011 г., а не 4 января 2011 г.
- «01.04.2011» — это также 1 апреля 2011 г. — начальные нули не нужны.
Как это сделать?
Вот что у меня есть до сих пор.
Управление поведением Date#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
... У меня получается 01.04.2011, а не 01.04.2011.
Управление поведением String#to_date
В настоящее время метод ActiveSupport String#to_date
выглядит следующим образом (source а>):
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
.)
Поскольку я знаю, что обычно буду передавать такие строки, как 01.04.2011 или 01.04.2011, я могу исправить это, исправив его следующим образом:
class String
# Keep a pointer to ActiveSupport's 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;
Это решение помогает пройти мои тесты, но разве это сумасшествие? Я просто где-то пропустил параметр конфигурации или есть какое-то другое, более простое решение?
Есть ли какие-либо другие случаи анализа даты, которые я не освещаю?