различия. Самое главное состоит в том, что класс Date вообще игнорирует время, то есть работает с точностью до одного дня. Кроме того, класс Date строже контролирует ошибки, чем класс Time: попытка обратиться к 31 июня (или к 29 февраля невисокосного года) приведет к исключению. Код даже «знает» о различных датах перехода на григорианский календарь в Италии и Англии (в 1582 и 1752 году соответственно) и может обнаружить «несуществующие» даты, появившиеся в результате такого перехода. Эта стандартная библиотека — паноптикум интересного и местами загадочного кода. К сожалению, у нас нет места для более подробного разговора о ней.

7.19. Взаимные преобразования объектов Date, Time и DateTime

В Ruby есть три основных класса для работы с датами и временем: Time, Date и DateTime. Опишем их особенности:

Класс Time преимущественно обертывает соответствующие функции из стандартной библиотеки языка С. Они, как правило, опираются на точку отсчета в UNIX и потому не способны представлять моменты времени раньше 1970 года.

Класс Date создан для преодоления недостатков класса Time. Он без труда справляется с датами в более отдаленном прошлом — например, позволяет представить день рождения Леонардо да Винчи (15 апреля 1452 года), и, кроме того, знает о реформе календаря. Но у него есть свои слабые места: он работает только с датами, игнорируя время.

Класс DateTime наследует Date и пытается компенсировать отсутствующие в нем возможности. Он может представлять даты не хуже Date и время не хуже Time. Часто его способ представления даты и времени оказывается наилучшим.

Однако не думайте, что объект DateTime — это просто объект Date, к которому механически присоединен объект Time. На самом деле в классе DateTime отсутствуют такие методы, как usec, dst? и некоторые другие.

Итак, у нас есть три класса. К сожалению, не существует стандартного способа преобразовать один из них в любой другой. По мере развития Ruby подобные шероховатости будут устраняться. А пока обойдемся методами, приведенными в листинге 7.2. Спасибо Кирку Хейнсу (Kirk Haines).

Листинг 7.2. Преобразования между классами, представляющими даты и время

class Time

 def to_date

  Date.new(year, month, day)

 rescue NameError

  nil

 end

 def to_datetime

  DateTime.new(year, month, day, hour, min, sec)

 rescue NameError

  nil

 end

end

class DateTime

 def to_time

   Time.local(year,month,day,hour,min,sec)

 end

end

class Date

 def to_time

  Time.local(year,month,day)

 end

end

Эти методы пропускают наверх все исключения, кроме NameError. Зачем нужно его перехватывать? Потому что могло случиться так, что программа не затребовала (с помощью директивы require) библиотеку date (напомним, что классы Date и DateTime входят в эту стандартную библиотеку, а не являются системными). В таком случае методы to_datetime и to_date возвращают nil.

7.20. Извлечение даты и времени из строки

Дата и время могут быть представлены в виде строки самыми разными способами: в полной или сокращенной форме, с разной пунктуацией, различным порядком компонентов и т.д. Из-за такого разнообразия очень сложно написать код, интерпретирующий символьную строку как дату. Рассмотрим несколько примеров:

s1 = '9/13/98 2:15am'

s2 = '1961-05-31'

s3 = '11 July 1924'

s4 = 'April 17, 1929'

s5 = '20 July 1969 16:17 EDT'

s6 = 'Mon Nov 13 2000'

s7 = 'August 24, 79' # День разрушения Помпеи.

s8 = '8/24/79'

К счастью, большую часть работы за нас уже проделали. В модуле ParseDate есть единственный класс с таким же именем, а в нем — единственный метод parsedate. Он возвращает массив компонентов даты в следующем порядке: год, месяц, день, час, минута, секунда, часовой пояс, день недели. Вместо полей, которые не удалось распознать, возвращается nil.

require 'parsedate.rb'

include ParseDate

p parsedate(s1)      # [98, 9, 13, 2, 15, nil, nil, nil]

p parsedate(s2)      # [1961, 5, 31, nil, nil, nil, nil, nil]

p parsedate(s3)      # [1924, 7, 11, nil, nil, nil, nil, nil]

p parsedate(s4)      # [1929, 4, 17, nil, nil, nil, nil, nil]

p parsedate(s5)      # [1969, 7, 20, 16, 17, nil, 'EDT', nil]

p parsedate(s6)      # [2000, 11, 13, nil, nil, nil, nil, 1]

p parsedate(s7)      # [79, 8, 24, nil, nil, nil, nil, nil]

p parsedate(s8,true) # [1979, 8, 24, nil, nil, nil, nil, nil]

Последние две строки иллюстрируют назначение второго параметра parsedate, который называется guess_year. Из-за привычки записывать год двумя цифрами может возникнуть неоднозначность. Последние две строки интерпретируются по-разному; при разборе

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату