Я не могу получить 15-й рабочий день в ruby

#ruby

#ruby

Вопрос:

Я не могу получить следующий 15-й день, но не рабочий день.

 DateTime.now.next_day( 15).strftime('%d %^B %Y')
  

как я могу получить следующий 15-й рабочий день?

Комментарии:

1. Не могли бы вы уточнить? Если 15-й день — выходные, вы хотите продолжить до понедельника?

2. business_time это готовое к использованию решение для такого рода проблем.

Ответ №1:

Вы просто добавляете 15 дней к текущей дате. Что вы хотите, так это скорректировать дату:

 date = DateTime.now

if (date.mday > 15)
  date = date.next_month
end

date = date.next_day(15 - date.mday)
  

Где это настраивается на 15-е число следующего месяца, если уже прошло 15-е число текущего месяца.

Теперь это может быть расширено, чтобы быть перечислителем:

 def each_mday(mday, from: nil)
  from ||= DateTime.now

  Enumerator.new do |y|
    loop do
      if (from.mday > mday)
        from = from.next_month
      end

      from = from.next_day(mday - from.mday)

      y << from

      from  = 1
    end
  end
end
  

Что позволяет найти первый день, соответствующий определенным критериям, например, будний день:

 each_mday(15, from: Date.parse('2019-06-14')).find { |d| (1..5).include?(d.wday) }
  

Где это возвращает 15 июля, поскольку 15 июня — выходные.

from Аргумент необязателен, но полезен для тестирования подобных случаев, чтобы убедиться, что он работает правильно.

Комментарии:

1. 15-й рабочий день будет 12 апреля, исключая все выходные. Но отправленный код: 2019-04-15T22:18:36 00:00

2. Добавлены параметры фильтрации, позволяющие находить только дни недели, или что-либо еще, что может потребоваться применить в качестве ограничения.

Ответ №2:

 15.times.reduce(Date.civil 2019, 03, 24) do |acc, _|
  begin
    acc  = 1
  end while [0, 6].include? acc.wday
  acc
end
#⇒ #<Date: 2019-04-12 ((2458586j,0s,0n), 0s,2299161j)>
  

Ответ №3:

Итак, вы хотите добавить 15 рабочих дней с текущей даты. Вы можете использовать iGian или Aleksei vanilla ruby answers или использовать gem business_time:

 15.business_days.from_now
  

Ответ №4:

Если я правильно понял, вы хотите получить следующий понедельник, если попадете в субботу или воскресенье. Поскольку wday дает вам 0 значения для Sun и 6 для Sat, вы можете использовать его в качестве условия для добавления дней к понедельнику.

 def date_add_next_week_day(days)
  date = (Date.today   days)
  date  = 1 if date.wday == 6
  date  = 1 if date.wday == 0
  date
end

date_add_next_week_day(15).strftime('%d %^B %Y')
  

Комментарии:

1. Я пробовал приведенный выше код, но он не исключает выходные.

2. ах, хорошо, значит, нужно добавить только рабочие дни

Ответ №5:

Если я правильно понял, вам нужно найти 15-й день после указанной даты, пропуская выходные.

Один из возможных вариантов — определить skipping_weekend хэш следующим образом, учитывая Date.html#wday:

 skip_weekend = { 6 => 2, 0 => 1}
skip_weekend.default = 0
  

Тогда:

 next15 = DateTime.now.next_day(15)
next15_working = next15.next_day(skip_weekend[next15.wday]).strftime('%d %B %Y')
  

Теперь, если next15 выпадает на рабочий день, next15_working это тот же день (хэш по умолчанию равен 0 ), в противном случае он пропускает 2 дня, если суббота (6-й день недели, хэш соответствует 2 ) или 1 день, если воскресенье (0-й день недели, хэш соответствует 1 )

Ответ №6:

Я предполагаю, что, учитывая начальную дату, ds ( Date объект) и положительное целое число n , проблема заключается в определении более поздней даты, dt такой, чтобы между ds 1 и dt включительно были n дни недели.

 require 'date'

def given_date_plus_week_days(dt, week_days)
  wday = dt.wday
  weeks, days = (week_days   {0=>4, 6=>4}.fetch(wday, wday-1)).divmod(5)
  dt - (wday.zero? ? 6 : (wday - 1))   7*weeks   days
end
  

Переменная wday присваивается дню недели для даты начала, dt . Дата начала переносится обратно на предыдущий понедельник, если только она не приходится на понедельник, и в этом случае она не изменяется. Это отражено в выражении

 wday.zero? ? 6 : (wday - 1)
  

который вычитается из dt . Количество дней недели соответствующим образом корректируется на

 week_days   { 0=>4, 6=>4 }.fetch(wday, wday-1)
  

Остальные вычисления просты.

 def display(start_str, week_days)    
  start = Date.parse(start_str)
  7.times.map { |i| start   i }.each do |ds|
    de = given_date_plus_week_days(ds, week_days)
    puts "#{ds.strftime("%a, %b %d, %Y")}   #{week_days} -> #{de.strftime("%a, %b %d, %Y")}"   
  end
end
  

 display("April 8", 15)
Mon, Apr 08, 2019   15 -> Mon, Apr 29, 2019
Tue, Apr 09, 2019   15 -> Tue, Apr 30, 2019
Wed, Apr 10, 2019   15 -> Wed, May 01, 2019
Thu, Apr 11, 2019   15 -> Thu, May 02, 2019
Fri, Apr 12, 2019   15 -> Fri, May 03, 2019
Sat, Apr 13, 2019   15 -> Fri, May 03, 2019
Sun, Apr 14, 2019   15 -> Fri, May 03, 2019
  

 display("April 8", 17)
Mon, Apr 08, 2019   17 -> Wed, May 01, 2019
Tue, Apr 09, 2019   17 -> Thu, May 02, 2019
Wed, Apr 10, 2019   17 -> Fri, May 03, 2019
Thu, Apr 11, 2019   17 -> Mon, May 06, 2019
Fri, Apr 12, 2019   17 -> Tue, May 07, 2019
Sat, Apr 13, 2019   17 -> Tue, May 07, 2019
Sun, Apr 14, 2019   17 -> Tue, May 07, 2019