Учитывая дату, как я могу эффективно рассчитать следующую дату в данной последовательности (еженедельно, ежемесячно, ежегодно)? - PullRequest
2 голосов
/ 23 февраля 2010

В моем приложении у меня есть различные последовательности дат, такие как Еженедельно, Ежемесячно и Ежегодно. Учитывая произвольную дату в прошлом, мне нужно вычислить следующую будущую дату в последовательности.

В данный момент я использую неоптимальный цикл. Вот упрощенный пример (в Ruby / Rails):

def calculate_next_date(from_date)
  next_date = from_date
  while next_date < Date.today
    next_date += 1.week # (or 1.month)
  end
  next_date
end

Вместо того, чтобы выполнять цикл (который хотя и прост, но неэффективен, особенно если дать дату в далеком прошлом), я хотел бы сделать это с арифметикой даты путем вычисления количества недель (или месяцев, лет) между две даты, вычисляя остаток и используя эти значения для генерации следующей даты.

Это правильный подход, или мне не хватает особенно умного «рубинового» способа решения этой проблемы? Или я должен просто придерживаться своей петли для простоты всего этого?

Ответы [ 3 ]

15 голосов
/ 23 февраля 2010

Поскольку вы пометили этот вопрос как ruby-on-rails, я полагаю, вы используете Rails. ActiveSupport представляет модуль вычисления , который предоставляет полезный метод #advance.

date = Date.today
date.advance(:weeks => 1)
date.advance(:days => 7)
# => next week
4 голосов
/ 23 февраля 2010

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

2 голосов
/ 23 февраля 2010

Если вы используете объект Time, вы можете использовать Time.to_a, чтобы разбить время на массив (с полями, представляющими час, день, месяц и т. Д.), Настроить соответствующее поле и передать массив обратно. на Time.local или Time.utc для создания нового Time объекта.

Если вы используете класс Date, date +/- n даст вам дату n дней спустя / раньше, а date >>/<< n даст вам дату n месяцев позже / раньше.

Вы можете использовать более общий Date.step вместо вашего цикла. Например,

from_date.step(Date.today, interval) {|d|
    # Each iteration of this block will be passed a value for 'd'
    #   that is 'interval' days after the previous 'd'.
}

, где interval - промежуток времени в днях.

Если все, что вы делаете, это вычисление прошедшего времени, то, вероятно, есть лучший подход к этому. Если ваша дата хранится как объект Date, выполнение date - Date.today даст вам количество дней между этой датой и временем. Для расчета месяцев, лет и т. Д. Вы можете использовать что-то вроде этого:

# Parameter 'old_date' must be a Date object
def months_since(old_date)
    (Date.today.month + (12 * Date.today.year)) - (old_date.month + (12 * old_date.year))
end
def years_since(old_date)
    Date.today.year - old_date.year
end
def days_since(old_date)
    Date.today - old_date
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...