Intro to timeperiodsR

Alexey Seleznev

2024-01-23

Цель пакета timeperiodsR

Зачастую при создании скриптов которые в последствии будут запускаться по расписанию нам необходимо определить некий отчётный период. Как правило, таким периодом может быть прошлая неделя, прошлый месяц, либо какое-то количество прошлых дней. Пакет timeperiodsR предоставляет вам набор функций которые автоматически будут вычислять такой период от заданной даты. Все функции пакета возвращают период в виде объекта класса tpr. В этой виньетке мы подробно разберём все функции пакета timeperiodsR, а также компоненты и методы класса tpr.

Содержание

Помимо данной виньетки к пакету timeperiodsR есть видео инструкция, ознакомится с которой можно по этой ссылке.

Простой пример использования

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

library(timeperiodsR)
#> 
#> ---------------------
#> Welcome to timeperiodsR version 0.7.3
#> 
#> Author:           Alexey Seleznev (Head of analytics dept at Netpeak).
#> Telegram channel: https://t.me/R4marketing 
#> Email:            selesnow@gmail.com
#> Blog:             https://alexeyseleznev.wordpress.com 
#> Facebook:         https://facebook.com/selesnown 
#> Linkedin:         https://www.linkedin.com/in/selesnow 
#> 
#> Type ?timeperiodsR for the main documentation.
#> The github page is: https://github.com/selesnow/timeperiodsR/
#> 
#> Suggestions and bug-reports can be submitted at: https://github.com/selesnow/timeperiodsR/issues
#> Or contact: <selesnow@gmail.com>
#> 
#>  To suppress this message use:  suppressPackageStartupMessages(library(timeperiodsR))
#> ---------------------

# получаем прошлый месяц
period <- previous_month()

# получаем начальную и конечную дату прошлого месяца
start <- period$start # первый день прошлого месяца
end   <- period$end   # последний день прошлого месяца

Код определения временно периода с помощью timeperiodsR компактен и легко читаем, таким же бразом вы можете определять и любые другие периоды, о чём вы более подробно узнаете из данной статьи.

Функции пакета timeperiodsR

Текущая версия пакета состоит из 24 функций, по названию каждой из функций можно определить какой временной интервал она возвращает. Название состоит из префикса last / previous / this / next и временной единицы day / week / month / quarter / year. Нижнее подчёркивание _ является разделителем слов в названиях функций.

Список функций

Компоненты получаемых объектов

Любая из функций пакета возвращает объект класса tpr состоящий из следующих компонентов:

Обязательные компоненты

Дополнительные компоненты

Начиная с версии timeperiodsR 0.5.0 в пакет была интегрирована поддержка API производственного календаря isDayOff. Этот API позволяет получить официальные праздничные дни в следующих странах: Россия, Украина, Казахстан и Белоруссия.

Для активации дополнительных компонентов вам необходимо установить пакет httr.

install.packages("httr")

По умолчанию дополнительные компоненты приведённые выше выключены, т.к. они нужны не всем пользователям пакета, а пакет с использованием API работает значительно медленнее.

Для расширения класса tpr дополнительными компонентами вы можете воспользоваться опциями или переменными среды.

Опции для включения дополнительных компонентов

  • timeperiodsR.official_day_offs - включение дополнительных компонентов, по умолчанию имеет значение FALSE;
  • timeperiodsR.official_day_offs_country - установить страну для которой будет запрашиваться список официальных выходных дней:
    • ru - Россия, значение по умолчанию;
    • ua - Украина
    • by - Белоруссия
    • kz - Казахстан
  • timeperiodsR.official_day_offs_pre - распознавать, что день предпраздничный, т.е. сокращённым:
    • 0 - без вывода сокращённых дней (по умолчанию)
    • 1 - распознавать, что день предпраздничный (сокращённый)

Пример установки опций:

options("timeperiodsR.official_day_offs" = TRUE,
        "timeperiodsR.official_day_offs_country" = "ua",
        "timeperiodsR.official_day_offs_pre" = 1)

Переменные среды для включения дополнительных компонентов

Опции удобны для работы, но их необходимо задавать при каждом новом сеансе работы с R, если все указанные в опциях параметры в большинстве случаев у вас статичны, то лучше задать их на уровне операционной системы.

О том как создавать переменные среды можно узнать из этого видео.

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

  • TPR_DAY_OFFS - TRUE, для активации дополнительных компонентов;
  • TPR_COUNTRY - Страна: ru, ua, by или kz;
  • TPR_PRE - Включать в компонент official_day_offs сокращённые рабочие дни, в компоненте dayoffs_marks они будут помечены числом 2.

После того как вы установите значения для переменных среды пакет автоматически будет считывать их при подключении.

Аргументы

В функциях пакета timeperiodsR присутствуют следующие аргументы:

Методы

Пакет timeperiodsR имеет несколько методов, позволяющих вам извлекать некоторые элементы объектов класса tpr.

last_n_*

Функции блока last_n_*() позволяют вам получить прошлый период с заданным количеством временных единиц.

Вместо * подставьте один из нужных вам временных интервалов: days, weeks, months, quarters, years

Например, допустим, что сегодня 26 сентября 2019 года и вам необходимо получить 2 прошлые недели то используйте функцию last_n_weeks():

last2weeks <- last_n_weeks(n = 2)
2 прошлые недели
2 прошлые недели

Код захватит даты с 9 по 22 сентября включительно.

После чего у вас появится объект last2weeks класса tpr. Из него вы легко можете получить начальную или конечную дату периода, а так же всю последовательность дат которая вошла в этот период, или количество дней вошедших в период.

# начальная дата
last2weeks$start
#> [1] "2024-01-08"
## или
start(last2weeks)
#> [1] "2024-01-08"

# конечная дата
last2weeks$end
#> [1] "2024-01-21"
## или
end(last2weeks)
#> [1] "2024-01-21"

# первый рабочий день
last2weeks$first_workday
#> [1] "2024-01-08"
## или
first_workday(last2weeks)
#> [1] "2024-01-08"

# последний рабочий день
last2weeks$last_workday
#> [1] "2024-01-19"
## или
last_workday(last2weeks)
#> [1] "2024-01-19"

# первый выходной день
last2weeks$first_weekend
#> [1] "2024-01-13"
## или
first_weekend(last2weeks)
#> [1] "2024-01-13"

# последний выходной день  
last2weeks$last_weekend
#> [1] "2024-01-21"
## или
last_weekend(last2weeks)
#> [1] "2024-01-21"

# последовательность дат
last2weeks$sequence
#>  [1] "2024-01-08" "2024-01-09" "2024-01-10" "2024-01-11" "2024-01-12"
#>  [6] "2024-01-13" "2024-01-14" "2024-01-15" "2024-01-16" "2024-01-17"
#> [11] "2024-01-18" "2024-01-19" "2024-01-20" "2024-01-21"
## или
seq(last2weeks)
#>  [1] "2024-01-08" "2024-01-09" "2024-01-10" "2024-01-11" "2024-01-12"
#>  [6] "2024-01-13" "2024-01-14" "2024-01-15" "2024-01-16" "2024-01-17"
#> [11] "2024-01-18" "2024-01-19" "2024-01-20" "2024-01-21"

# последовательность будних дней
last2weeks$workdays
#>  [1] "2024-01-08" "2024-01-09" "2024-01-10" "2024-01-11" "2024-01-12"
#>  [6] "2024-01-15" "2024-01-16" "2024-01-17" "2024-01-18" "2024-01-19"
## или
workdays(last2weeks)
#>  [1] "2024-01-08" "2024-01-09" "2024-01-10" "2024-01-11" "2024-01-12"
#>  [6] "2024-01-15" "2024-01-16" "2024-01-17" "2024-01-18" "2024-01-19"

# последовательность выходных дней
last2weeks$weekends
#> [1] "2024-01-13" "2024-01-14" "2024-01-20" "2024-01-21"
# или
weekends(last2weeks)
#> [1] "2024-01-13" "2024-01-14" "2024-01-20" "2024-01-21"

# количество дней вошедших в период
last2weeks$length
#> [1] 14
## или
length(last2weeks)
#> [1] 14

# количество будних дней в периоде
last2weeks$workdays_length
#> [1] 10
## или
workdays_length(last2weeks)
#> [1] 10
  
# количество выходных дней в периоде
last2weeks$weekends_length
#> [1] 4
## или
weekends_length(last2weeks)
#> [1] 4

Во всех функциях предназначенных для работы с неделями т.е. last_n_weeks(), previous_week(), this_week(), next_week(), next_n_weeks() присутствует аргумент week_start, с его помощью можно указать день недели который будет являться её началом. По умолчанию неделя начинается с понедельника, т.е. week_start = 1, но вы можете задать и любой другой день:

  1. Понедельник
  2. Вторник
  3. Среда
  4. Четверг
  5. Пятница
  6. Суббота
  7. Воскресенье

Т.е. если вы хотите получить 2 предыдущие недели отталкиваясь от 26 сентября, и при этом необходимо считать началом недели воскресенье то используйте следующий код:

library(timeperiodsR)

last2weeks <- last_n_weeks(x = "2019-09-26", n = 2, week_start = 7)
Две предыдущие недели, начало недели воскресенье
Две предыдущие недели, начало недели воскресенье

previous_*

Функции блока previous_*() позволяют вам получить прошлый период со смещением на заданное количеством временных единиц. Т.е. например получить позапрошлую неделю.

Вместо * подставьте один из нужных вам временных интервалов: week, month, quarter, year

Допустим нам необходимо получить позапрошлую неделю отталкиваясь от 26 сентября 2019 года, началом недели должен быть понедельник

previous2weeks <- previous_week(x = "2019-09-26", n = 2)
Позапрошлая неделя
Позапрошлая неделя

this_*

Функции блока this_*() позволяют вам получить текущий период.

Вместо * подставьте один из нужных вам временных интервалов: week, month, quarter, year

Если вам необходимо получить первую и последнюю дату текущего месяца, и всю последовательность дат которые в него входят, то используйте следующий код:

this_month()
#> 
#>  Time period: 2024-01-01 (понедельник) - 2024-01-31 (среда)
Текущий месяц
Текущий месяц

Т.е. если сегодня 26 сентября 2019 года функция this_month() захватит весь сентябрь 2019 года.

next_*

Функции блока next_*() противоположный функциям блока previous_*(). Т.е. позволяют вам получить будущий период со смещением на заданное количеством временных единиц. Т.е. например получить следующую неделю от 12 сентября.

Вместо * подставьте один из нужных вам временных интервалов: week, month, quarter, year


nextweek_from_12sep <- next_week("2019-09-12")

nextweek_from_today <- next_week()
Следующая неделя
Следующая неделя

next_n_*

Блок next_n_* позволяет создать период обратный от того, что создают функции блока last_n_*, т.е. получить будущий период с заданным количеством временных единиц.

Вместо * подставьте один из нужных вам временных интервалов: days, weeks, months, quarters, years

Например если вам необходимо получить 5 следующих дней воспользуйтесь следующим кодом.

# получить 5 следующих дней не включая текущую дату
next5days <- next_n_days(n = 5)

# получить 5 следующих дней включая текущую дату
next5days_wt <- next_n_days(n = 5, include_current = T)

custom_period

Данная функция позволяет создавать объект класса tpr с любым произвольным периодом.

period1 <- custom_period("2019-09-03", "2019-09-11")

Операторы

В timeperiodsR есть несколько операторов.

Из представленного описания возможно сложно понять зачем эти операторы нужны, и как именно они работают. Поэтому рассмотрим несколько примеров.

Сначала создадим два объекта tpr класса, относительно 7 ноября 2019 года. Один будет соответствовать текущему месяцу, а второй предыдущей неделе.

period1 <- this_month("2019-11-07")
period2 <- previous_week("2019-11-07")

print(period1)
#> 
#>  Time period: 2019-11-01 (пятница) - 2019-11-30 (суббота)
print(period2)
#> 
#>  Time period: 2019-10-28 (понедельник) - 2019-11-03 (воскресенье)

В таком случае первый период содержит даты с 1 по 30 ноября, а второй с 28 октября по 3 ноября. Т.е. частично эти два периода пересекаются и мы можем фильтровать один из используя значения другого.

period1 %left_in% period2   # получить даты из period1 которые входят в period2
#> [1] "2019-11-01" "2019-11-02" "2019-11-03"
period1 %left_out% period2  # получить даты из period1 которые не входят в period2
#>  [1] "2019-11-04" "2019-11-05" "2019-11-06" "2019-11-07" "2019-11-08"
#>  [6] "2019-11-09" "2019-11-10" "2019-11-11" "2019-11-12" "2019-11-13"
#> [11] "2019-11-14" "2019-11-15" "2019-11-16" "2019-11-17" "2019-11-18"
#> [16] "2019-11-19" "2019-11-20" "2019-11-21" "2019-11-22" "2019-11-23"
#> [21] "2019-11-24" "2019-11-25" "2019-11-26" "2019-11-27" "2019-11-28"
#> [26] "2019-11-29" "2019-11-30"
period1 %right_in% period2  # получить даты из period2 которые входят в period1
#> [1] "2019-11-01" "2019-11-02" "2019-11-03"
period1 %right_out% period2 # получить даты из period2 которые не входят в period2
#> [1] "2019-10-28" "2019-10-29" "2019-10-30" "2019-10-31"

Такие операторы фильтрации удобно использовать например при проверке наличия данных в базе за какой-то период, в тех случаях когда вы наполняете базу данными из внешних источников на ежедневной основе.

К примеру вы каждый день запрашиваете данные из API Google Analytics, и записываете их в базу. При этом API периодически может давать сбой, и за какой-то день в вашей базе будут отсутствовать данные, тогда вы можете определить проверочный период, например предыдущие 30 дней, с помощью команды last_n_days(n = 30). Далее запрашивать данные за этот из вашей СУБД. После, с помощью приведённых выше операторов фильтрации убрать из общего 30 дневного периода даты которые присутствуют в базе, и по оставшимся датам подгрузить данные.

Конвертация различных объектов в класс tpr

Вы можете преобразоватьвектор из дат, или строковый вектор состоящий из дат в формате YYYY-MM-DD в объект класса tpr с помощью функции as_timeperiod().

dates <- c("2019-09-11", "2019-09-02", "2019-10-11", "2019-08-30")
dates_tpr <- as_timeperiod(dates)
dates_tpr
#> 
#>  Time period: 2019-08-30 (пятница) - 2019-10-11 (пятница)

В приведённом выше примере конвертации строкового вектора в объект класса tpr, исходный вектор содержит 4 даты, они идут в произвольном порядке, и в целом между ними много пропущенных дней, т.е. данный вектор не является непрерывной последовательностью дат. В таком случае функция as_timeperiod() находит в исходном векторе минимальную и максимальную дату, и создаёт объект класса tpr равный временному интервалу между этими двумя датами.

Пользовательские выходные дни

Иногда помимо официальных выходных дней вам может понадобиться выделить собственные дополнительные выходные дни, например ваш отпуск. Пакет timeperiodsR даёт вам такую возможность с помощью опции или переменной среды.

В опцию timeperiodsR.custom_day_offs вы можете передать вектор с датами которые будут помечены как дополнительные выходные дни, такие дни в компоненте dayoffs_marks будут помечены значением 3.

Также вы можете задать переменную среды TPR_CUSTOM_DAY_OFFS, в которой укажите даты в формате ГГГГ-ММ-ДД разделённые запятыми или точками с запятой.

Таким образом вы можете помечать дополнительные выходные дни.

options("timeperiodsR.custom_day_offs" = c("2020-01-14", "2020-01-15", "2020-01-16", "2020-01-17", "2020-02-12"))
tm <- this_month("2020-01-01")

# получить ваши пользовательские выходные которые входят в текущий период
tm$custom_day_offs
#> [1] "2020-01-14" "2020-01-15" "2020-01-16" "2020-01-17"

# пользовательские выходные будут помечены 3
tm$dayoffs_marks
#> 2020-01-01 2020-01-02 2020-01-03 2020-01-04 2020-01-05 2020-01-06 2020-01-07 
#>        "1"        "0"        "0"        "1"        "1"        "1"        "1" 
#> 2020-01-08 2020-01-09 2020-01-10 2020-01-11 2020-01-12 2020-01-13 2020-01-14 
#>        "0"        "0"        "0"        "2"        "1"        "0"        "3" 
#> 2020-01-15 2020-01-16 2020-01-17 2020-01-18 2020-01-19 2020-01-20 2020-01-21 
#>        "3"        "3"        "3"        "1"        "1"        "0"        "0" 
#> 2020-01-22 2020-01-23 2020-01-24 2020-01-25 2020-01-26 2020-01-27 2020-01-28 
#>        "0"        "0"        "0"        "1"        "1"        "0"        "0" 
#> 2020-01-29 2020-01-30 2020-01-31 
#>        "0"        "0"        "0"