Книга: Программирование на языке Ruby

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 года).

Оглавление книги

Оглавление статьи/книги

Генерация: 1.329. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз