#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