Ответ 1
Gem: ruby-american_date
Этот камень был создан, так как я задал этот вопрос. Я сейчас использую его и был доволен.
Я нахожусь в США, и мы обычно форматируем даты как "месяц/день/год". Я пытаюсь убедиться, что мое приложение Rails, использующее Ruby 1.9, принимает этот формат везде и работает так, как это было в Ruby 1.8.
Я знаю, что у многих людей есть эта проблема, поэтому я хотел бы создать окончательное руководство здесь.
В частности:
Как я могу это сделать?
Вот что я до сих пор.
У меня есть эта строка в 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".
В настоящее время метод 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;
Это решение заставляет мои тесты проходить, но это безумие? Я просто пропускаю параметр конфигурации где-нибудь или есть другое, более простое решение?
Существуют ли какие-либо другие случаи синтаксиса даты, которые я не закрываю?
Этот камень был создан, так как я задал этот вопрос. Я сейчас использую его и был доволен.
Date.strptime
- это, вероятно, то, что вы ищете в ruby 1.9.
Вы, вероятно, застряли в monkeypatching его на string.to_date, но strptime - лучшее решение для синтаксического анализа дат из строк в ruby 1.9.
Также, насколько мне известно, форматы симметричны с strftime.
вы можете использовать rails-i18n gem или просто скопировать en-US.yml и установите стандартную локаль "ru-US" в config/application.rb
Для разбора дат в стиле США вы можете использовать:
Date.strptime(date_string, '%m/%d/%Y')
В консоли:
> Date.strptime('04/01/2011', '%m/%d/%Y')
=> Fri, 01 Apr 2011
> Date.strptime('4/1/2011', '%m/%d/%Y')
=> Fri, 01 Apr 2011
Использовать REE?: D
Серьезно, хотя. Если это небольшое приложение, которое вы полностью контролируете или стандартизируете в этом формате даты, исправление обезьян для проекта вполне разумно. Вам просто нужно убедиться, что все ваши входы поступают с правильным форматом, будь то через API или веб-сайт.
Вместо использования to_s для экземпляров Date, привыкнуть использовать strftime. Он принимает строку формата, которая дает вам полный контроль над форматом даты.
Изменить: strptime дает вам полный контроль над синтаксическим анализом, указав также строку формата. Вы можете использовать одну и ту же строку формата в обоих методах.
Другой вариант - Chronic - http://chronic.rubyforge.org/
Вам просто нужно установить префикс endian для форматирования только формата даты MM/DD/YYYY:
Chronic::DEFAULT_OPTIONS[ :endian_precedence ] = [ :middle ]
Однако значение по умолчанию для Chronic - это формат даты, не соответствующий порядковым номерам США!