7.5. Вычисление n-ого дня недели в месяце

7.5. Вычисление n-ого дня недели в месяце

Иногда, зная год и месяц, хочется вычислить дату, скажем, третьего понедельника или второго вторника в этом месяце. Такую задачу решает код в листинге 7.1.

Чтобы найти n-ое вхождение данного дня недели, мы передаем n в качестве первого параметра. Второй параметр — номер дня недели (0 — воскресенье, 1 — понедельник и т.д.). Третий и четвертый параметры — месяц и год соответственно.

Листинг 7.1. Вычисление n-ого дня недели в месяце

def nth_wday(n, wday, month, year)

 if (!n.between? 1,5) or

  (!wday.between? 0,6) or

  (!month.between? 1,12) raise ArgumentError

 end

 t = Time.local year, month, 1

 first = t.wday

 if first == wday

  fwd = 1

 elsif first < wday

  fwd = wday - first + 1

 elsif first > wday

  fwd = (wday+7) - first + 1

 end

 target = fwd + (n-1)*7

 begin

  t2 = Time.local year, month, target

 rescue ArgumentError

  return nil

 end

 if t2.mday == target

  t2

 else

  nil

 end

end

Странный код в конце текста метода призван скорректировать давнюю традицию, принятую в функциях работы с датами. Если вы думаете, что попытка создать объект для представления 31 ноября приведет к ошибке, то разочарую вас. Почти все системы молчаливо преобразуют эту дату в 1 декабря. Если вы давным-давно программируете в UNIX, то, наверное, полагаете, что так и должно быть. Другие сочтут это ошибкой.

Не станем спорить о том, что должна делать системная библиотека и должен ли Ruby изменить это поведение. Но мы не хотим, чтобы наша процедура продолжала эту традицию. Если вы ищете, к примеру, пятую пятницу в ноябре 2000 года, то она вернет nil (а не 1 декабря 2000 года).

Данный текст является ознакомительным фрагментом.