2016-12-07 3 views
1

Я бы хотел рассчитать дату окончания с даты начала. У меня есть количество рабочих дней (так что без воскресенья и субботы). Это моя функция:Как получить будущую дату благодаря количеству рабочих дней в рубине?

def ending_date(start_date, number_of_working_days) 
    date = 0 
    ending_date = start_date 
    while date > number_of_working_days 
    next if ending_date.sunday? || ending_date.saturday? 
    finish = ending_date + 1.day unless date.saturday? or date.sunday? 
    date += 1 
    end 
    finish 
end 

И я получаю nil. Я не знаю почему. Если somedoby может помочь мне с этим, пожалуйста :)

+0

'дата> number_of_working_days' => '0> number_of_working_days' –

ответ

0

С минимальными изменениями он должен выглядеть так:

def ending_date(start_date, number_of_working_days) 
    date = 0 
    while date < number_of_working_days 
    start_date += 1 
    unless start_date.saturday? || start_date.sunday? 
     finish = start_date 
     date += 1 
    end 
    end 
    finish 
end 

#> ending_date(Date.today, 5) 
#=> #<Date: 2016-12-14 ((2457737j,0s,0n),+0s,2299161j)> 

Но я предпочитаю, чтобы написать этот метод как-то так:

def ending_date(date, number_of_working_days) 
    result = [] 
    while result.size < number_of_working_days 
    date += 1 
    unless [6,0].include? date.wday 
     result << date 
    end 
    end 
    result 
end 

# To take all the working dates 
#> ending_date(Date.today, 5) 
#=> [#<Date: 2016-12-08 ((2457731j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-09 ((2457732j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-12 ((2457735j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-13 ((2457736j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-14 ((2457737j,0s,0n),+0s,2299161j)>] 

# To take last working date 
#> ending_date(Date.today, 5).last 
#=> #<Date: 2016-12-14 ((2457737j,0s,0n),+0s,2299161j)> 
+0

Действительно'> 'был в неправильном пути! Этот путь должен работать. Но моя консоль поворачивается навсегда, и ничего не происходит, как если бы это было в бесконечной петле. – Orsay

1

Enumerator кажется для выполнения этой работы, и он может предоставить вам гораздо больше информации, чем просто дату:

require 'date' 

def future_working_days(start_date = Date.today) 
    date = start_date 
    Enumerator.new do |yielder| 
    loop do 
     date += 1 # NOTE: Should start_date be included? 
     yielder << date unless date.saturday? || date.sunday? 
    end 
    end 
end 

def ending_date(number_of_working_days, start_date = Date.today) 
    future_working_days(start_date).find.with_index(1) { |_, i| i == number_of_working_days } 
end 

# Show the next 10 working days : 
puts future_working_days.take(10).map(&:to_s).join('->') # 2016-12-08->2016-12-09->2016-12-12->2016-12-13->2016-12-14->2016-12-15->2016-12-16->2016-12-19->2016-12-20->2016-12-21 

# Date after 5 working days : 
puts ending_date(5) #=> 2016-12-14 

# How many working days until the next Friday the 13th of a leap year 
puts future_working_days.find_index{|date| date.friday? && date.day == 13 && Date.leap?(date.year)} #=> 851 

Примечания:

  • Параметры ending_date были включены, чтобы дата по умолчанию для датой_начала
  • future_working_days бесконечное Enumerator. Не пытайтесь future_working_days.to_a! Lazy может быть полезно.
  • Должно ли сегодня быть включено в future_working_days?
+0

Согласно моему коду, я просто понимаю, что мне лучше сделать этот метод в javascript! :(Я собираюсь опубликовать ваше решение в новом вопросе для перевода его в js! Не стесняйтесь помогать. Еще раз спасибо – Orsay

+0

См. Мой другой ответ: должно быть довольно просто реализовать его в javascript –

1

Также можно рассчитать ending_date напрямую, без какого-либо цикла. Каждые 5 рабочих дней на выходных! Я написал код для воскресенья как start_date и изменил его на start_date.wday на другие дни недели. Суббота - особый случай.

def ending_date(number_of_working_days, start_date = Date.today) 
    if start_date.wday == 6 # Saturday is a special case 
    start_date + number_of_working_days + (number_of_working_days-1)/5*2 + 1 
    else 
    start_date + number_of_working_days + (number_of_working_days-1+start_date.wday)/5*2 
    end 
end 

Я проверил это для многих start_dates и многих number_of_working_days, и это, кажется, работает хорошо.

Я не мог найти способ удалить оператор if.

EDIT: Если вы работаете с ActiveSupport::TimeWithZone объектами, просто позвоните to_date перед вызовом ending_date:

time = Time.zone.local(2016, 10, 15, 15, 30, 45) 
puts time.class     #=> ActiveSupport::TimeWithZone 
puts ending_date(5, time.to_date) #=> 2016-10-21 
+0

Я предпочитаю это решение, немного легче читать! Однако мой формат даты начала - «ActiveSupport :: TimeWithZone», поэтому он не работает, знаете ли вы, что мне нужно изменить? Я очень смущен форматом даты, это непростая вещь. – Orsay

+0

См. Просто используйте 'TimeWithZone # to_date'. –

+0

Благодарим за помощь! – Orsay

Смежные вопросы