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

У меня есть диапазон дат (от, до), который я хочу прокручивать через разные интервалы (ежедневно, еженедельно, ежемесячно,...)

Как я могу перебирать эти диапазоны дат?

Обновить

Спасибо за ответы, у меня получилось следующее:

interval = 'week' # month, year
start = from
while start < to
  stop  = start.send("end_of_#{interval}")
  if stop > to
    stop = to
  end
  logger.debug "Interval from #{start.inspect} to #{stop.inspect}"
  start = stop.send("beginning_of_#{interval}")
  start += 1.send(interval)
end

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

Поскольку я не упомянул об этом в своем вопросе, я выбрал ответ, который подтолкнул меня в правильном направлении.


person tonymarschall    schedule 12.05.2012    source источник


Ответы (4)


Зацикливаться до тех пор, пока дата from плюс 1.day, 1.week или 1.month не превысят дату to?

 > from = Time.now
 => 2012-05-12 09:21:24 -0400 
 > to = Time.now + 1.month + 2.week + 3.day
 => 2012-06-29 09:21:34 -0400 
 > tmp = from
 => 2012-05-12 09:21:24 -0400 
 > begin
?>   tmp += 1.week
?>   puts tmp
?> end while tmp <= to
2012-05-19 09:21:24 -0400
2012-05-26 09:21:24 -0400
2012-06-02 09:21:24 -0400
2012-06-09 09:21:24 -0400
2012-06-16 09:21:24 -0400
2012-06-23 09:21:24 -0400
2012-06-30 09:21:24 -0400
 => nil 
person Dave Newton    schedule 12.05.2012
comment
[ссылка] stackoverflow.com/ questions/501253/ Xenofex answer более удобен в использовании - person Sector; 12.05.2012
comment
@Sector Это то же самое, завернутое в метод. - person Dave Newton; 12.05.2012
comment
если наступит конец месяца, например, 2014-06-30, он не сможет увеличить день до 1 июля, есть ли какое-либо решение? - person peterlawn; 04.07.2014

В Ruby 1.9 я добавил свой собственный метод Range для пошагового перехода по временным диапазонам:

class Range
  def time_step(step, &block)
    return enum_for(:time_step, step) unless block_given?

    start_time, end_time = first, last
    begin
      yield(start_time)
    end while (start_time += step) <= end_time
  end
end

Затем вы можете назвать это как, например. (В моем примере используется специальный метод Rails: 15 минут):

irb(main):001:0> (1.hour.ago..Time.current).time_step(15.minutes) { |time| puts time }
2012-07-01 21:07:48 -0400
2012-07-01 21:22:48 -0400
2012-07-01 21:37:48 -0400
2012-07-01 21:52:48 -0400
2012-07-01 22:07:48 -0400
=> nil

irb(main):002:0> (1.hour.ago..Time.current).time_step(15.minutes).map { |time| time.to_s(:short) }
=> ["01 Jul 21:10", "01 Jul 21:25", "01 Jul 21:40", "01 Jul 21:55", "01 Jul 22:10"]

Обратите внимание, что этот метод использует соглашение Ruby 1.9, согласно которому методы перечисления возвращают перечислитель, если блок не задан, что позволяет вам объединять перечислители в строку.

ОБНОВИТЬ

Я добавил метод Range#time_step в свою личную core_extensions "жемчужину". Если вы хотите использовать это в своем проекте Rails, просто добавьте в свой Gemfile следующее:

gem 'core_extensions', github: 'pdobb/core_extensions'
person pdobb    schedule 02.07.2012
comment
Хорошо, я должен был найти этот ответ раньше, это сэкономило бы мне время! Написал очень похожую реализацию для добавления ActiveSupport::Durations к Range#step stackoverflow.com/questions/19093487/ruby-create-range-of-dates/ - person captainpete; 17.10.2013

Метод succ устарел в диапазоне 1.9. Желая делать то же самое по неделям, я пришел к такому решению:

  def by_week(start_date, number_of_weeks)
    number_of_weeks.times.inject([]) { |memo, w| memo << start_date + w.weeks }
  end

Это возвращает массив недель в интервале. Легко адаптируется в течение нескольких месяцев.

person tal    schedule 22.03.2013

У вас есть метод step для объекта Range. http://ruby-doc.org/core-1.9.3/Range.html#method-i-step

person Cristian Bica    schedule 12.05.2012
comment
Можете ли вы привести пример? Вы не можете повторяться со временем, так что это не просто шаг через 1.week и т.д. - person Dave Newton; 12.05.2012
comment
Здесь вы можете сделать некоторые базовые вещи: (Date.current - 5.months.. Date.current).step(7){#code}, (Date.current - 5.months.. Date.current).step(1 ){#код} - person Cristian Bica; 12.05.2012
comment
Я думаю, вы можете повторять время, но это будет очень медленно, так как будет создавать элемент в диапазоне каждую секунду. - person Cristian Bica; 12.05.2012
comment
Не в 1.9 нельзя, AFAICT, ультравысокий Я не делал это простым инт. - person Dave Newton; 12.05.2012
comment
Ага... с 1.9 нельзя делать диапазоны по времени. Range работает, вызывая метод succ для начального значения диапазона, а в версии 1.9 метод succ по времени устарел... - person Cristian Bica; 12.05.2012