t1 = Time.gm(*Time.now.to_a)
Однако, глядя на первый пример, не думайте, что вы сможете изменить вычисляемые параметры, например день недели (в данном случае 2 означает вторник). Такое действие противоречило бы принципам организации календаря, поэтому на созданном объекте Time
оно никак не отражается. 20 ноября 1979 года был вторник, и никакой код не сможет этого изменить.
И наконец, отметим, что есть много способов задать время некорректно, например указав тринадцатый месяц или 35-й день месяца. При любой подобной попытке возникнет исключение ArgumentError
.
7.3. Определение дня недели
Есть несколько способов определить день недели. Во-первых, метод экземпляра to_a
возвращает массив, содержащий всю информацию о моменте времени. Можно обратиться к его седьмому элементу; это число от 0 до 6, причем 0 соответствует воскресенью, а 6 — субботе.
time = Time.now
day = time.to_a[6] # 2 (вторник)
Еще лучше воспользоваться методом экземпляра wday
:
day = time.wday # 2 (вторник)
Но и тот, и другой способ не очень удобны. Иногда нужно получить день недели в виде числа, но чаще нас интересует его название в виде строки. Для этого можно обратиться к методу strftime
. Его название знакомо программистам на С. Он распознает около двадцати спецификаторов, позволяя по-разному форматировать дату и время (см. раздел 7.21).
day = time.strftime('%а') # 'Tue'
Можно получить и полное название:
long = time.strftime('%А') # 'Tuesday'
7.4. Определение даты Пасхи
Дату этого праздника всегда было сложно вычислить, так как она привязана к лунному календарю. Солнечный год не делится нацело на лунные месяцы, поэтому даты, основанные на таком исчислении времени, будут из года в год меняться.
Представленный ниже алгоритм хорошо известен с давних времен. Мы видели его реализацию на языках BASIC, Pascal и С. А теперь перевели и на Ruby:
def easter(year)
с = year/100
n = year - 19*(year/19)
k = (c-17)/25
i = с - c/4 - (c-k)/3 + 19*n + 15
i = i - 30*(i/30)
i = i - (i/28)* (1 -(i/28)*(29/(i + 1))*((21-n)/11))
j = year + year/4 + i + 2 - с + c/4
j = j - 7*(j/7)
l = i - j
month = 3 + (1+40)/44
day = l + 28 — 31*(month/4)
[month, day]
end
date = easter 2001 # Найти месяц и день для 2001 года,
date = [2001] + date # Добавить в начало год.
t = Time.local *date # Передать параметры Time.local.
puts t # Sun Apr 15 01:00:00 GMT-8:00 2001
Кто-то, прочитав этот раздел о Пасхе, непременно спросит: «Церковная или астрономическая?» Честно говоря, не знаю. Если вам удастся выяснить, сообщите всем нам.
Я бы с удовольствием объяснил вам этот алгоритм, только вот сам его не понимаю… Что-то надо принимать на веру, а в данном случае это особенно уместно!
7.5. Вычисление n-ого дня недели в месяце
Иногда, зная год и месяц, хочется вычислить дату, скажем, третьего понедельника или второго вторника в этом месяце. Такую задачу решает код в листинге 7.1.
Чтобы найти n-ое вхождение данного дня недели, мы передаем n в качестве первого параметра. Второй параметр — номер дня недели (0 — воскресенье, 1 — понедельник и т.д.). Третий и четвертый параметры — месяц и год соответственно.
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 ноября