> For the complete documentation index, see [llms.txt](https://evgenii-afanasev.gitbook.io/ruby-course/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://evgenii-afanasev.gitbook.io/ruby-course/2_basics/6_datetime.md).

# Работа с датой и временем

## Работа с датой и временем

В этом курсе вы узнаете, как использовать класс Time, чтобы представлять время, дату и продолжительность временных интервалов.

### Создание временой метки

Для начала давайте посмотрим как получить объект Time содержащий информацию о текущем либо произвольном времени:

```ruby
# Получение информации о текущей дате и времени
now = Time.now # = 2023-03- 15:43:20 +0200
# Альернативный споосб получения текущего даты и времени
now = Time.new # = 2018-10-19 15:43:20 +0200
# Получение объекта с информацией о времени за конкретный день
# формат Time.new(год, месяц, день)
custom = Time.new(2018, 1, 1) # = 2018-01-01 00:00:00 +0100
# формат Time.new(год, месяц, день, час, минута, секунда, отступ часового пояса по UTC)
custom = Time.new(2002, 10, 31, 2, 2, 2, "+02:00") # = 2002-10-31 02:02:02 +0200
zone = timezone("Europe/Moscow") # Московский часовой пояс, UTC+3
# формат Time.new(год, месяц, день, час, минута, секунда, часовой пояс по UTC)
custom = Time.new(2002, 10, 31, 2, 2, 2, zone)  # = 2002-10-31 02:02:02 +0300
# Поучение объекта Time прозводный от Timestamp (POSIX-время, количество секунд прошедшее с 00:00:00 UTC 1 января, 1970 года)
custom = Time.at(15000000000) # = 2017-07-14 04:40:00 +0200
```

### Форматирование времени

За частую, во время работы со временем нам нужно превращать его в строку, либо наборот, превращать строку в метку времени.

Для того, чтобы перевести Time в строковое представление используется метод `.strftime(format)` в который передается формат записи времени. Так как форматов записи может быть огромное множество, то был создан способ описания формата времени:

* %Y - год в формате с 4-мя цифрами (например, 2022)
* %m - номер месяца с предваряющим нулем (например, 01 для января)
* %d - день месяца с предваряющим нулем (например, 01)
* %H - часы в 24-часовом формате с предваряющим нулем (например, 02 для 2 часов утра или 2 часов дня)
* %M - минуты с предваряющим нулем
* %S - секунды с предваряющим нулем
* %z - Часов

Это лишь список наиболее часто используемых форматов, более подробное описание форматов можете поискать сами по необходимости.

Кроме того, эти форматы мы можем комбинировать между собой как это показано в примере ниже:

```ruby
time = Time.new(2022, 1, 1, 11, 20, 35)
puts time.strftime("%d/%m/%Y - %H:%M") # = 01/01/2022 - 11:20
puts time.strftime("%m.%y %H:%M:S") # = 01.2022 11:20:35
```

Для того, чтобы нам теперь перевести строку в метку времени нам необходимо расширить возможности класса `Time` с помощью добавления `require 'time'` в самом начале нашего `.rb` файла, после чего мы сможем воспользоваться конструкцией `Time.strptime(str, format)`. В качестве первого аргумента мы передаем строкове представление метки времени (например `"01/01/2022 - 11:20"`), а в качестве формата мы передаем формат записи (например `%d/%m/%Y - %H:%M`).

```ruby
require 'time'

time = Time.new(2022, 1, 1, 11, 20, 35)
date_format = "%d/%m/%Y - %H:%M"
str_time = time.strftime(date_format) # метод возвращает строковое представление 
puts str_time # = "01/01/2022 - 11:20"
decoded_dtime = Time.strptime(str_time, date_format) # метод возвращает метку времени 
p decoded_dtime # = Time ( 2022-01-01 11:20:00 +0300 )
```

Помимо прочего существует конструкция `Time.parse(str)`, которая автоматически подбирает формат из предстановленных спецификаций RFC, но во первых, далеко не любой формат так можно распарсить, а во вторых, этот метод парсит строку с помощью перебоора формата: попробовал распарсить - не получилось - пробует еще раз с другим форматом и так до тех пора, пока не получится. Указывая формат напрямую мы избавляемся от лишних действий6 которые за нас сделает сам язык.

### Арифметические операции со временем

Хорошо, мы научились создавать метку времени, научились превращать ее в строку, теперь стоит изучить способы манипуляции со временем.

У метки времени есть возможность прибавлять и убавлять время с помощью привычных для нас операторов `-` и `+`. Обратите внимание, прибавляются **секунды**.

```ruby
time = Time.new(2022, 1, 1, 11, 20, 35)
puts time.strftime("%%d/m/%y %H:%M:S") # = "01/01/2022 - 11:20:35"
# альтернатвная запись выражения time = time + 5
time += 5
puts time.strftime("%%d/m/%y %H:%M:S") # = "01/01/2022 - 11:20:40"
# альтернатвная запись выражения time = time - 2
time -= 2
puts time.strftime("%%d/m/%y %H:%M:S") # = "01/01/2022 - 11:20:38"
```

### Вычисление разницы между двумя временами

Также мы можем вычитать метки времени между собой для нахождения разницы между ними в **секундах**

```ruby
start = Time.new(2022, 1, 1, 11, 20, 35)
finish = Time.new(2022, 1, 1, 11, 20, 40)

puts finish - start # 5
```

Вычитание одной метки времени и другой - это излюбленный способ для замера продолжительности выполнения время выполнения кода

```ruby
start = Time.now
sleep(5) # заставляем программу 'засыпать' на 5 секунд
finish = Time.now
puts finish - start # = 5.0... секунд
```

## Задание birthdays

Реализуйте метод `collect_birthdays(year, month, day)`, который будет печатать в консоль ваш возраст, дата дня рождения и день недели вашего дня рождения

Как это должно выглядеть:

```ruby
  collect_birthdays(1997, 12, 1)

  # 0 - 01.12.1997 - Monday
  # 1 - 01.12.1998 - Tuesday
  # 2 - 01.12.1999 - Wednesday
  # ...
  # 25 - 01.12.2022 - Thursday
```

### Дополнительный материал

* [Работа со временем и датой](https://www.rubyguides.com/2015/12/ruby-time/)
* [официальная документация по Time](https://ruby-doc.org/3.2.1/Time.html)
* [Еще одна документация по Time из stdlib](https://ruby-doc.org/3.2.1/stdlibs/time/Time.html)
* [Официальная документация по форматированию](https://ruby-doc.org/3.2.1/strftime_formatting_rdoc.html)
