--- title: "Intro to timeperiodsR" author: "Alexey Seleznev" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Intro to timeperiodsR} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( eval=TRUE, collapse = TRUE, comment = "#>" ) ``` # Цель пакета timeperiodsR Зачастую при создании скриптов которые в последствии будут запускаться по расписанию нам необходимо определить некий отчётный период. Как правило, таким периодом может быть прошлая неделя, прошлый месяц, либо какое-то количество прошлых дней. Пакет timeperiodsR предоставляет вам набор функций которые автоматически будут вычислять такой период от заданной даты. Все функции пакета возвращают период в виде объекта класса *tpr*. В этой виньетке мы подробно разберём все функции пакета `timeperiodsR`, а также компоненты и методы класса *tpr*. # Содержание * Простой пример использования * Функции пакета * Компоненты класса tpr * Аргументы * Методы * Операторы * Конвертация других объектов в класс tpr * Пользовательские выходные дни Помимо данной виньетки к пакету `timeperiodsR` есть видео инструкция, ознакомится с которой можно по этой [ссылке](https://youtu.be/NgfWELbM6Fk). # Простой пример использования Как я уже писал выше, основная цель `timeperiodsR` упростить процесс определения относительного периода. Если у вас есть скрипт который запускается по рассписанию, и собирает данные за прошлый месяц, то вы можете получить прошлый месяц следующим образом: ```{r, echo=TRUE, eval=TRUE} library(timeperiodsR) # получаем прошлый месяц period <- previous_month() # получаем начальную и конечную дату прошлого месяца start <- period$start # первый день прошлого месяца end <- period$end # последний день прошлого месяца ``` Код определения временно периода с помощью `timeperiodsR` компактен и легко читаем, таким же бразом вы можете определять и любые другие периоды, о чём вы более подробно узнаете из данной статьи. # Функции пакета timeperiodsR Текущая версия пакета состоит из 24 функций, по названию каждой из функций можно определить какой временной интервал она возвращает. Название состоит из префикса `last` / `previous` / `this` / `next` и временной единицы `day` / `week` / `month` / `quarter` / `year`. Нижнее подчёркивание `_` является разделителем слов в названиях функций. ## Список функций * `last_n_days()` * `last_n_weeks()` * `last_n_months()` * `last_n_quarters()` * `last_n_years()` * `previous_week()` * `previous_month()` * `previous_quarter()` * `previous_year()` * `this_week()` * `this_month()` * `this_quarter()` * `this_year()` * `next_week()` * `next_month()` * `next_quarter()` * `next_year()` * `next_n_days()` * `next_n_weeks()` * `next_n_months()` * `next_n_quarters()` * `next_n_years()` * `custom_period()` * `as_timeperiod()` * `check_dayoffs()` ## Компоненты получаемых объектов Любая из функций пакета возвращает объект класса `tpr` состоящий из следующих компонентов: **Обязательные компоненты** * start - начальная дата; * end - конечная дата; * first_workday - первый рабочий день; * last_workday - последний рабочий день; * first_weekend - первый выходной день; * last_weekend - последний выходной день; * sequence - последовательность дат; * workdays - последовательность будних дней; * weekends - последовательность выходных дней; * length - количество дней входящих в период; * workdays_length - количество будних дней входящих в период; * weekends_length - количество выходных дней входящих в период; **Дополнительные компоненты** * official_workdays - Официальные рабочие дни; * official_first_workday - Первый официальный рабочий день; * official_last_workday - Последний официальный рабочий день; * official_day_offs - официальные выходные дни в выбранной стране, по умолчанию России; * custom_day_offs - пользовательские выходные дни; * dayoffs_marks - пометки о том, какой статус имеет день в официальном календаре страны; * custom_day_offs - пользовательские выходные. Начиная с версии `timeperiodsR 0.5.0` в пакет была интегрирована поддержка API производственного календаря [isDayOff](https://isdayoff.ru/). Этот API позволяет получить официальные праздничные дни в следующих странах: Россия, Украина, Казахстан и Белоруссия. Для активации дополнительных компонентов вам необходимо установить пакет `httr`. ```{r eval=FALSE} 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 - распознавать, что день предпраздничный (сокращённый) Пример установки опций: ```{r eval=TRUE} options("timeperiodsR.official_day_offs" = TRUE, "timeperiodsR.official_day_offs_country" = "ua", "timeperiodsR.official_day_offs_pre" = 1) ``` #### Переменные среды для включения дополнительных компонентов Опции удобны для работы, но их необходимо задавать при каждом новом сеансе работы с R, если все указанные в опциях параметры в большинстве случаев у вас статичны, то лучше задать их на уровне операционной системы. О том как создавать переменные среды можно узнать из этого [видео](https://www.youtube.com/watch?v=zoNvu2T6IFc&list=PLD2LDq8edf4pItOb-vZTG5AXZK2niJ8_R&index=5&t). Задайте следующие переменные среды для того, что бы не указывать опции в каждом сеансе: * TPR_DAY_OFFS - TRUE, для активации дополнительных компонентов; * TPR_COUNTRY - Страна: ru, ua, by или kz; * TPR_PRE - Включать в компонент *official_day_offs* сокращённые рабочие дни, в компоненте *dayoffs_marks* они будут помечены числом 2. После того как вы установите значения для переменных среды пакет автоматически будет считывать их при подключении. ## Аргументы В функциях пакета timeperiodsR присутствуют следующие аргументы: * *x* - Объект даты, от которой будет вычисляться интервал, по умолчанию это текущий день; * *n* - Количество временных интервалов на которое необходимо сместится от даты указанной в аргументе *x*; * *part* - Какую часть объекта вам необходимо получить: * "all" - объект со всеми доступными компонентами; * "start" - начальную дату; * "end" - конечную дату; * "first_workday" - первый рабочий день периода; * "last_workday" - последний рабочий день периода; * "first_weekend" - первый выходной день периода; * "last_weekend" - последний выходной день периода; * "sequence" - последовательность дат; * "workdays" - последовательность будних дней в периоде; * "weekends" - последовательность выходных дней в периоде; * "length" - количество дней входящих в период; * "workdays_length" - количество будних дней входящих в период; * "weekends_length" - количество выходных дней входящих в период; * "official_workdays" - официальные рабочие дни для указанной страны; * "official_first_workday" - первый официальный рабочий день для указанной страны; * "official_last_workday" - последний официальный рабочий день для указанной страны; * "official_day_offs" - официальные выходные дни для указанной страны; * "dayoffs_marks" - пометки для каждого дня; * *week_start* - Какой день будет являться началом недели: 1 - понедельник, 7 - воскресенье; * *include_current* - Включать ли в период текущий временной объект, TRUE или FALSE. ## Методы Пакет `timeperiodsR` имеет несколько методов, позволяющих вам извлекать некоторые элементы объектов класса *tpr*. * `seq` - получить последовательность дат из объекта класса *tpr*; * `length` - получить длительность объекта класса *tpr* в днях; * `start` - получить первую дату из объекта класса *tpr*; * `end` - получить последнюю дату из объекта класса *tpr*; * `first_workday` - получить первый рабочий день из объекта класса *tpr*; * `last_workday` - получить последний рабочий день из объекта класса *tpr*; * `first_weekend` - получить первый выходной день из объекта класса *tpr*; * `last_weekend` - получить последний выходной из объекта класса *tpr*; * `workdays` - получить последовательность рабочих дней из объекта класса *tpr*; * `weekends` - получить последовательность выходных из объекта класса *tpr*; * `workdays_length` - получить из объекта класса *tpr*; * `weekends_length` - получить из объекта класса *tpr*; * `print` - вывести в консоль информацию о периоде содержащемся в объекте класса *tpr*. # last\_n\_\* Функции блока `last_n_*()` позволяют вам получить прошлый период с заданным количеством временных единиц. Вместо `*` подставьте один из нужных вам временных интервалов: *days, weeks, months, quarters, years* Например, допустим, что сегодня 26 сентября 2019 года и вам необходимо получить 2 прошлые недели то используйте функцию `last_n_weeks()`: ```{r, echo=TRUE, eval=TRUE} last2weeks <- last_n_weeks(n = 2) ``` ![2 прошлые недели](http://img.netpeak.ua/alsey/156864246904_kiss_75kb.png) Код захватит даты с 9 по 22 сентября включительно. После чего у вас появится объект **last2weeks** класса `tpr`. Из него вы легко можете получить начальную или конечную дату периода, а так же всю последовательность дат которая вошла в этот период, или количество дней вошедших в период. ```{r, echo=TRUE, eval=TRUE} # начальная дата last2weeks$start ## или start(last2weeks) # конечная дата last2weeks$end ## или end(last2weeks) # первый рабочий день last2weeks$first_workday ## или first_workday(last2weeks) # последний рабочий день last2weeks$last_workday ## или last_workday(last2weeks) # первый выходной день last2weeks$first_weekend ## или first_weekend(last2weeks) # последний выходной день last2weeks$last_weekend ## или last_weekend(last2weeks) # последовательность дат last2weeks$sequence ## или seq(last2weeks) # последовательность будних дней last2weeks$workdays ## или workdays(last2weeks) # последовательность выходных дней last2weeks$weekends # или weekends(last2weeks) # количество дней вошедших в период last2weeks$length ## или length(last2weeks) # количество будних дней в периоде last2weeks$workdays_length ## или workdays_length(last2weeks) # количество выходных дней в периоде last2weeks$weekends_length ## или weekends_length(last2weeks) ``` Во всех функциях предназначенных для работы с неделями т.е. `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 сентября, и при этом необходимо считать началом недели воскресенье то используйте следующий код: ```{r, echo=TRUE} library(timeperiodsR) last2weeks <- last_n_weeks(x = "2019-09-26", n = 2, week_start = 7) ``` ![Две предыдущие недели, начало недели воскресенье](http://img.netpeak.ua/alsey/156864661236_kiss_74kb.png) # previous\_\* Функции блока `previous_*()` позволяют вам получить прошлый период со смещением на заданное количеством временных единиц. Т.е. например получить позапрошлую неделю. Вместо `*` подставьте один из нужных вам временных интервалов: *week, month, quarter, year* Допустим нам необходимо получить позапрошлую неделю отталкиваясь от 26 сентября 2019 года, началом недели должен быть понедельник ```{r, echo=TRUE} previous2weeks <- previous_week(x = "2019-09-26", n = 2) ``` ![Позапрошлая неделя](http://img.netpeak.ua/alsey/156863814902_kiss_70kb.png) # this\_\* Функции блока `this_*()` позволяют вам получить текущий период. Вместо `*` подставьте один из нужных вам временных интервалов: *week, month, quarter, year* Если вам необходимо получить первую и последнюю дату текущего месяца, и всю последовательность дат которые в него входят, то используйте следующий код: ```{r, echo=TRUE} this_month() ``` ![Текущий месяц](http://img.netpeak.ua/alsey/156880445292_kiss_73kb.png) Т.е. если сегодня 26 сентября 2019 года функция `this_month()` захватит весь сентябрь 2019 года. # next\_\* Функции блока `next_*()` противоположный функциям блока `previous_*()`. Т.е. позволяют вам получить будущий период со смещением на заданное количеством временных единиц. Т.е. например получить следующую неделю от 12 сентября. Вместо `*` подставьте один из нужных вам временных интервалов: *week, month, quarter, year* ```{r, echo=TRUE} nextweek_from_12sep <- next_week("2019-09-12") nextweek_from_today <- next_week() ``` ![Следующая неделя](http://img.netpeak.ua/alsey/156881039998_kiss_72kb.png) # next\_n\_\* Блок `next_n_*` позволяет создать период обратный от того, что создают функции блока `last_n_*`, т.е. получить будущий период с заданным количеством временных единиц. Вместо `*` подставьте один из нужных вам временных интервалов: *days, weeks, months, quarters, years* Например если вам необходимо получить 5 следующих дней воспользуйтесь следующим кодом. ```{r, echo=TRUE} # получить 5 следующих дней не включая текущую дату next5days <- next_n_days(n = 5) # получить 5 следующих дней включая текущую дату next5days_wt <- next_n_days(n = 5, include_current = T) ``` # custom_period Данная функция позволяет создавать объект класса *tpr* с любым произвольным периодом. ```{r, echo=TRUE} period1 <- custom_period("2019-09-03", "2019-09-11") ``` # Операторы В `timeperiodsR` есть несколько операторов. * %.in% - проверяет вхождение одного вектора дат, или объекта класса tpr в другой, и возвращает логический вектор. * %left_out% - сравнивает два объекта класса tpr, и возвращает значение из левого, которые отсутствуют в правом. * %left_in% - сравнивает два объекта класса tpr, и возвращает даты из левого объекта которые входят в правый * %right_out% - сравнивает два объекта класса tpr, и возвращает значение из правого, которые отсутствуют в левом. * %right_in% - сравнивает два объекта класса tpr, и возвращает даты из правого объекта которые присутствуют в левом. Из представленного описания возможно сложно понять зачем эти операторы нужны, и как именно они работают. Поэтому рассмотрим несколько примеров. Сначала создадим два объекта tpr класса, относительно 7 ноября 2019 года. Один будет соответствовать текущему месяцу, а второй предыдущей неделе. ```{r, echo=TRUE} period1 <- this_month("2019-11-07") period2 <- previous_week("2019-11-07") print(period1) print(period2) ``` В таком случае первый период содержит даты с 1 по 30 ноября, а второй с 28 октября по 3 ноября. Т.е. частично эти два периода пересекаются и мы можем фильтровать один из используя значения другого. ```{r, echo=TRUE} period1 %left_in% period2 # получить даты из period1 которые входят в period2 period1 %left_out% period2 # получить даты из period1 которые не входят в period2 period1 %right_in% period2 # получить даты из period2 которые входят в period1 period1 %right_out% period2 # получить даты из period2 которые не входят в period2 ``` Такие операторы фильтрации удобно использовать например при проверке наличия данных в базе за какой-то период, в тех случаях когда вы наполняете базу данными из внешних источников на ежедневной основе. К примеру вы каждый день запрашиваете данные из API Google Analytics, и записываете их в базу. При этом API периодически может давать сбой, и за какой-то день в вашей базе будут отсутствовать данные, тогда вы можете определить проверочный период, например предыдущие 30 дней, с помощью команды `last_n_days(n = 30)`. Далее запрашивать данные за этот из вашей СУБД. После, с помощью приведённых выше операторов фильтрации убрать из общего 30 дневного периода даты которые присутствуют в базе, и по оставшимся датам подгрузить данные. # Конвертация различных объектов в класс tpr Вы можете преобразоватьвектор из дат, или строковый вектор состоящий из дат в формате *YYYY-MM-DD* в объект класса *tpr* с помощью функции `as_timeperiod()`. ```{r, echo=TRUE} dates <- c("2019-09-11", "2019-09-02", "2019-10-11", "2019-08-30") dates_tpr <- as_timeperiod(dates) dates_tpr ``` В приведённом выше примере конвертации строкового вектора в объект класса *tpr*, исходный вектор содержит 4 даты, они идут в произвольном порядке, и в целом между ними много пропущенных дней, т.е. данный вектор не является непрерывной последовательностью дат. В таком случае функция `as_timeperiod()` находит в исходном векторе минимальную и максимальную дату, и создаёт объект класса *tpr* равный временному интервалу между этими двумя датами. # Пользовательские выходные дни Иногда помимо официальных выходных дней вам может понадобиться выделить собственные дополнительные выходные дни, например ваш отпуск. Пакет `timeperiodsR` даёт вам такую возможность с помощью опции или переменной среды. В опцию `timeperiodsR.custom_day_offs` вы можете передать вектор с датами которые будут помечены как дополнительные выходные дни, такие дни в компоненте *dayoffs_marks* будут помечены значением 3. Также вы можете задать переменную среды `TPR_CUSTOM_DAY_OFFS`, в которой укажите даты в формате ГГГГ-ММ-ДД разделённые запятыми или точками с запятой. Таким образом вы можете помечать дополнительные выходные дни. ```{r, echo=TRUE} 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 # пользовательские выходные будут помечены 3 tm$dayoffs_marks ```