Как я могу использовать даты в американском стиле в Rails, используя Ruby 1.9?

Я живу в США, и мы обычно форматируем даты как месяц/день/год. Я пытаюсь убедиться, что мое приложение Rails, использующее Ruby 1.9, везде принимает этот формат и работает так же, как в Ruby 1.8.

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

Конкретно:

  1. «01.04.2011» — это 1 апреля 2011 г., а не 4 января 2011 г.
  2. «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;

Это решение помогает пройти мои тесты, но разве это сумасшествие? Я просто где-то пропустил параметр конфигурации или есть какое-то другое, более простое решение?

Есть ли какие-либо другие случаи анализа даты, которые я не освещаю?


person Nathan Long    schedule 02.09.2011    source источник
comment
Или вы могли бы переехать куда-нибудь, где форматы даты согласованы и используются метрическая и цельсийская системы ;-)   -  person Benoit Garret    schedule 02.09.2011
comment
@Benoit Garret - Эй, я согласен с вами по метрике и по Цельсию, но, на мой взгляд, ни один из форматов даты не является действительно логичным. Он должен быть максимально конкретным, например, 31-01-2011, потому что вы получаете информацию, которую вряд ли узнаете в первую очередь.   -  person Nathan Long    schedule 02.09.2011
comment
Вы имеете в виду, что 2011-01-31 является допустимым форматом даты в США?   -  person Benoit Garret    schedule 02.09.2011


Ответы (7)


Драгоценный камень: ruby-american_date

Этот драгоценный камень был создан, так как я задал этот вопрос. Сейчас пользуюсь и доволен.

https://github.com/jeremyevans/ruby-american_date

person Nathan Long    schedule 03.01.2012

Date.strptime, вероятно, то, что вы ищете в ruby ​​1.9.

Вы, вероятно, застряли на данный момент, исправляя его на string.to_date, но strptime — лучшее решение для разбора дат из строк в ruby ​​1.9.

Кроме того, насколько я знаю, форматы симметричны с strftime.

person Mainguy    schedule 12.09.2011

вы можете использовать гем rails-i18n или просто скопировать en-US.yml и установите локаль по умолчанию "en- США" в config/application.rb

person airy    schedule 14.09.2011

Для разбора дат в американском стиле вы можете использовать:

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 
person Tony - Currentuser.io    schedule 01.05.2014

Использовать РЭИ? :D

Если серьезно. Если это небольшое приложение, над которым у вас есть полный контроль, или вы стандартизируете этот формат даты, исправление обезьяны для проекта вполне разумно. Вам просто нужно убедиться, что все ваши входные данные поступают в правильном формате, будь то через API или веб-сайт.

person Joel Meador    schedule 02.09.2011
comment
Спасибо за подтверждение. :) Раньше мы использовали REE, но предпочли бы использовать MRI 1.9.2. Лично я надеюсь получить Rubinius, когда он будет готов, потому что он больше похож на Ruby, чем на Ruby сам по себе, и имеет потрясающую сборку мусора и отладку, а также стабильный объем памяти. - person Nathan Long; 02.09.2011
comment
В 1.9.2 много чего есть. Он также имеет много несоответствий с 1.8. Я также пытаюсь получить его во всем новом, и в нем много сюрпризов, подобных тому, о котором вы спрашиваете. :( - person Joel Meador; 02.09.2011

Вместо использования to_s для экземпляров Date возьмите за привычку использовать strftime. Он принимает строку формата, которая дает вам полный контроль над форматом даты.

Изменить: strptime дает вам полный контроль над синтаксическим анализом, указав также строку формата. Вы можете использовать одну и ту же строку формата в обоих методах.

person M. Scott Ford    schedule 04.09.2011
comment
Хорошее предложение. Для отображения дат мы на самом деле обычно используем помощник представления для всего приложения, поэтому мы можем везде быть согласованными и указать наш формат только один раз. Настоящей проблемой для меня был String#to_date, поскольку он используется Ripple (Riak ORM), чтобы брать введенные пользователем даты и превращать их в объекты Date в качестве свойств модели. Но я хотел, чтобы эта страница была всеобъемлющей. - person Nathan Long; 06.09.2011

Другим вариантом является Хронический — http://chronic.rubyforge.org/.

Вам просто нужно установить предпочтение endian, чтобы использовать только формат даты MM/DD/YYYY:

Chronic::DEFAULT_OPTIONS[ :endian_precedence ] = [ :middle ]

Однако по умолчанию для Chronic в любом случае используется нестандартный формат даты в США!

person Ben Walding    schedule 19.09.2011