В Ruby 12 месяцев! = 1 год - PullRequest
       34

В Ruby 12 месяцев! = 1 год

11 голосов
/ 13 ноября 2010

Помощники Руби по дате / времени полезны, но я нашел несоответствие.Кажется, 12.months не равен 1.year.Отметьте 1.month, и вы увидите, что он равен 30.days и, конечно, 12 * 30.days = 360.days, на 5,25 дня меньше фактической продолжительности года.

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

def months_to_seconds(number_of_months)
  ( (number_of_months.to_f / 12) * 1.year).to_i.seconds
end

Возвращает количество секунд в любой доле года, представленной number_of_months.

Так как 1.year равен в секундах 365.25дни, почему вы полагаете, что у них не было 1.month возвращает секунды в течение 1/12 года вместо 30 дней?

Кто-нибудь сталкивался с этим раньше?У кого-нибудь есть лучшее решение?

Ответы [ 4 ]

24 голосов
/ 13 ноября 2010

Календарь и время в целом - такая произвольная вещь, изобилующая такими несоответствиями.Стандартной длины «месяца» не существует, так как вариация колеблется от 28 до 31 дня, точно так же как не существует стандартной длины «дня», которая может составлять от 23 до 25 часов, и даже минута может иметь значение отОт 59 до 62 секунд, когда учитываются «високосные секунды».Аналогичным образом, год может составлять 365 или 366 дней, или даже 351, как это было в 1582 году.

Если вы не выполняете вычисления, специфичные для определенного интервала, например, количества секунд между 3 января 2010 года и октябрем19, 2011, вы не сможете узнать, как долго интервал использует абстрактные месяцы, дни или годы.Эти вещи зависят от огромного числа факторов.

Ваше решение подходит для вашего приложения, но в терминах Rails "месяц" - это просто 30 дней ради простоты, также как "день" - это 24 часа..

9 голосов
/ 13 ноября 2010

Да и нет:

12 months - это то же самое, что и 1 year, когда вы используете их в качестве относительных интервалов, потому что тогда они не преобразуются в секунды:

t = Time.now
#=> 2010-11-12 22:34:57 0100
t - 1.year == t - 12.months
#=> true

Внутренне эти интервалы хранятся в виде массивов числа лет, месяцев и дней, поэтому, если вы скажете, например:

1.year - 12.months
#=> 1 year and -12 months

это означает, что вычитание привело к интервалу, составляющему «один год и минус 12 месяцев».

Но если вы to_i их, их нужно преобразовать в точное количество секунд, и кто-то решил, что «месяц» означает «30 дней», что является таким же хорошим приближением, как и любое другое, пока вы придерживаетесь .

Это указано в документах:

Хотя эти методы обеспечивают точное расчет при использовании как в примеры выше, следует проявлять осторожность отметить, что это не так, если результат «месяцев», «лет» и т. д. перед использованием переделано

Полагаю, эти интервалы можно считать «лениво оцененными».

0 голосов
/ 13 ноября 2010
require 'date'

expire_date = Date.today >> 36
puts expire_date #=> 2013-11-12

Если вы хотите вычесть месяцы, используйте <<. </p>

0 голосов
/ 13 ноября 2010

1 год состоит из 12 отдельных месяцев, но несколько из этих месяцев имеют разные размеры. Учитывая, что месяц может фактически составлять 28, 29, 30 или 31 календарный день, разумно ожидать, что любое данное определение продолжительности месяца может не соответствовать желаемому.

Лично я использую 4 недели как определение месяца в большинстве случаев. В этом случае, когда вы предоставляете доступ на «месяц», я склонен хранить день месяца, когда доступ был предоставлен. Затем возьмите номер месяца и поместите срок действия в тот же день месяца, а затем N номеров месяца.

...