Чтение онлайн

ЖАНРЫ

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

Метод

Time.gm
, по сути, делает то же самое, но в нем предполагается время GMT (или UTC). Поскольку автор книги проживает в центральном часовом поясе США, то разница составляет 8 часов:

t8 = Time.gm(2001,3,15,21,30,15) # March 15, 2001 21:30:15 pm

# Это 13:30:15 по центральному времени!

У этого метода есть синоним

Time.utc
:

t9 = Time.utc(2001,3,15,21,30,15) # March 15, 2001 21:30:15 pm

# Снова 13:30:15 по центральному времени.

Отметим

одну важную вещь. Все эти методы могут принимать и альтернативный набор параметров. Метод экземпляра
to_a
(который преобразует время в массив отдельных компонентов) возвращает набор значений в следующем порядке: секунды, минуты, часы, день, месяц, год, день недели (
0..6
), порядковый номер дня в году (
1..366
), летнее время (
true
или
false
), часовой пояс (строка). Поэтому такие вызовы тоже допустимы:

t0 = Time.local(0,15,3,20,11,1979,2,324,false,"GMT-8:00")

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 — понедельник и т.д.). Третий и четвертый параметры — месяц и год соответственно.

Листинг 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

Поделиться с друзьями: