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

Производственный календарь, т.е. список дат, где соответствующим образом помечены все официальные рабочие и выходные дни — совершенно необходимая штука для любого пользователя Microsoft Excel. На практике без него не обойтись:

  • в бухгалтерских расчетах (зарплата, стаж, отпуска…)
  • в логистике — для корректного определения сроков доставки с учётом выходных и праздников (помните классическое «давай уже после праздников?»)
  • в управлении проектами — для правильной оценки сроков с учётом, опять же, рабочих-нерабочих дней
  • при любом использовании функций типа РАБДЕНЬ (WORKDAY) или ЧИСТРАБДНИ (NETWORKDAYS), т.к. они требуют в качестве аргумента список праздников
  • при использовании функций Time Intelligence (типа TOTALYTD, TOTALMTD, SAMEPERIODLASTYEAR и т.д.) в Power Pivot и Power BI
  • … и т.д. и т.п. — примеров масса.

Тем, кто работает в корпоративных ERP-системах типа 1С или SAP — проще, в них производственный календарь встроен. Но что делать пользователям Excel?

Можно, конечно, вести такой календарь вручную. Но тогда придется как минимум раз в год (а то и чаще, как в «весёлом» 2020 году) его актуализировать, аккуратно внося туда все выходные, переносы и нерабочие дни, придуманные нашим правительством. А потом повторять эту процедуру каждый следующий год. Скукота.

А как насчёт чуть напрячься и сделать «вечный» производственный календарь в Excel? Такой, чтобы сам обновлялся, брал данные из интернета и формировал всегда актуальный список нерабочих дней для последующего использования в любых расчетах? Заманчиво?

Сделать такое, на самом деле, совсем не сложно.

Источник данных

Главный вопрос — а где брать данные? В поисках подходящего источника я перебрал несколько вариантов:

  • Оригинальные указы публикуются на сайте правительства в формате PDF (вот, один из них, например) и отпадают сразу — полезную информацию из них не вытащить.
  • Заманчивым вариантом, на первый взгляд, казался «Портал открытых данных РФ», где есть соответствующий набор данных, но, при ближайшем изучении всё оказалось печально. Для импорта в Excel сайт жутко неудобен, техподдержка не отвечает (самоизолировались?), да и сами данные там давно устарели — производственный календарь на 2020 год обновлялся последний раз в ноябре 2019 (позорище!) и, само-собой, не содержит наших «коронавирусных» и «голосовательных» выходных 2020 года, например.

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

И вот в процессе поисков случайно обнаружилось прекрасное — сайт http://xmlcalendar.ru/

Сайт xmlcalendar.ru

Без лишних «рюшечек», простой, легкий и быстрый сайт, заточенный под одну задачу — отдавать всем желающим производственный календарь за нужный год в XML-формате. Отлично!

Если, вдруг, вы не в курсе, то XML — это текстовый формат с разметкой содержимого специальными <тегами>. Легкий, удобный и читаемый большинством современных программ, включая Excel.

Я, на всякий случай, связался с авторами сайта и они подтвердили, что сайт существует уже 7 лет, данные на нем постоянно актуализируются (у них для этого даже ветка на github есть) и закрывать его они не собираются. И совершенно не против, чтобы мы с вами с него грузили данные для любых наших проектов и расчётов в Excel. Бесплатно. Как же приятно, что есть еще такие люди! Респектище!

Осталось загрузить эти данные в Excel с помощью надстройки Power Query (для версий Excel 2010-2013 её можно бесплатно скачать с сайта Microsoft, а в версиях Excel 2016 и новее — она уже встроена по умолчанию).

Логика действий будет такая:

  1. Делаем запрос для загрузки данных с сайта за один любой год
  2. Превращаем наш запрос в функцию
  3. Применяем эту функцию к списку всех имеющихся лет, начиная с 2013 и до текущего года — и получаем «вечный» производственный календарь с автоматическим обновлением. Вуаля!

Шаг 1. Импортируем календарь за один год

Сначала загрузим производственный календарь за один любой год, например, за 2020. Для этого в Excel идём на вкладку Данные (или Power Query, если вы установили её как отдельную надстройку) и выбираем Из интернета (From Web). В открывшееся окно вставляем ссылку на соответствующий год, скопированную с сайта:

Грузим данные с сайта через Power Query

После нажатия на ОК появляется окно предварительного просмотра, в котором нужно нажать кнопку Преобразовать данные (Transform data) или Изменить данные (Edit data) и мы попадем в окно редактора запросов Power Query, где и продолжим работу с данными:

Окно Power Query

Сразу же можно смело удалить в правой панели Параметры запроса (Query settings) шаг Измененный тип (Changed Type) — он нам не нужен.

Таблица в столбце holidays содержит коды и описания нерабочих дней — увидеть её содержимое можно, дважды «провалившись» в неё щелчком мыши по зелёному слову Table:

Проваливаемся в таблицу праздников

Для возврата назад придется удалить в правой панели все появившиеся шаги обратно до Источника (Source).

Вторая таблица, куда можно зайти аналогичным образом, содержит как раз то, что нам нужно — даты всех нерабочих дней:

Таблица выходных

Останется эту табличку обработать, а именно:

1. Отфильтровать только даты праздников (т.е. единички) по второму столбцу Attribute:t

Удаляем лишние столбцы

2. Удалить все столбцы, кроме первого — щелчком правой кнопкой мыши по заголовку первого столбца и выбором команды Удалить другие столбцы (Remove Other Columns):

Удаляем лишние столбцы

3. Разделить первый столбец по точке отдельно на месяц и день с помощью команды Разделить столбец — По разделителю на вкладке Преобразование (Transform — Split column — By delimiter):

Делим по точке на месяц и день

4. И, наконец, создать вычисляемый столбец с нормальными датами. Для этого на вкладке Добавление столбца жмём на кнопку Настраиваемый столбец (Add Column — Custom Column) и вводим в появившееся окно следующую формулу:

Создаем столбец с датами

=#date(2020, [#»Attribute:d.1″], [#»Attribute:d.2″])

Здесь у оператора #date три аргумента: год, месяц и день, соответственно. После нажатия на ОК получаем требуемый столбец с нормальными датами выходных, а остальные столбцы удаляем как в п.2

Готовый список нерабочих дней

Шаг 2. Превращаем запрос в функцию

Следующая наша задача — преобразовать созданный на 2020 год запрос в универсальную функцию для любого года (номер года будет её аргументом). Для этого делаем следующее:

1. Разворачиваем (если ещё не развернута) панель Запросы (Queries) слева в окне Power Query:

Панель запросов

2. После преобразования запроса в функцию возможность видеть шаги, из которых состоит запрос и легко их редактировать, к сожалению, пропадает. Поэтому имеет смысл сделать копию нашего запроса и резвиться уже с ней, а оригинал оставить про запас. Для этого щелкаем правой кнопкой мыши в левой панели по нашему запросу calendar и выбираем команду Дублировать (Duplicate).

Щелкнув еще раз правой по получившейся копии calendar(2) выберем команду Переименовать (Rename) и введём новое имя — пусть будет, например, fxYear:

Копируем исходный запрос

3. Открываем исходный код запроса на внутреннем языке Power Query (он лаконично назвается «М») с помощью команды Расширенный редактор на вкладке Просмотр (View — Advanced Editor) и вносим туда небольшие правки для превращения нашего запроса в функцию на любой год.

Было:

Было

Стало:

Стало

Если интересны подробности, то здесь:

  • (year as number)=>  — объявляем, что в нашей функции будет один числовой аргумент — переменная year
  • Подклеиваем переменную year в веб-ссылку на шаге Источник. Поскольку Power Query не позволяет склеивать числа и текст, то на лету преобразовываем номер года в текст с помощью функции Number.ToText
  • Подставляем переменную year вместо 2020 года на предпоследнем шаге #»Добавлен пользовательский объект«, где мы формировали дату из фрагментов.

После нажатия на Готово наш запрос превращается в функцию:

Запрос превратился в функцию

Шаг 3. Импортируем календари за все года

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

1. Щёлкаем в левой панели запросов в серое пустое место правой кнопкой мыши и выбираем последовательно Новый запрос — Другие источники — Пустой запрос (New Query — From other sources — Blank query):

Создаем пустой запрос

2. Нам нужно сформировать список всех лет, для которых мы будем запрашивать календари, т.е. 2013, 2014 … 2020. Для этого в строке формул появившегося пустого запроса вводим команду:

Формируем список лет

Конструкция:

={ЧислоА..ЧислоБ}

… в Power Query формирует список целых чисел от А до Б. Например, выражение

={1..5}

…выдало бы список 1,2,3,4,5.

Ну, а чтобы не привязываться жёстко к 2020 году, мы используем функцию DateTime.LocalNow() — аналог экселевской функции СЕГОДНЯ (TODAY) в Power Query — и извлекаем из неё, в свою очередь, текущий год функцией Date.Year.

3. Полученный набор лет хоть и выглядит вполне адекватно, но для Power Query представляет собой не таблицу, а особый объект — список (List). Но преобразовать его в таблицу — не проблема: достаточно нажать кнопку В таблицу (To Table) в левом верхнем углу:

Преобразуем список в таблицу

4. Финишная прямая! Применяем созданную нами ранее функцию fxYear к полученному списку лет. Для этого на вкладке Добавление столбца жмём кнопку Вызвать настраиваемую функцию (Add Column — Invoke Custom Function) и задаём её единственный аргумент — колонку Column1 с годами:

Вызываем функцию fxYear

После нажатия на ОК наша функция fxYear по очереди отработает импорт для каждого года и мы получим столбец, где в каждой ячейке будет содержаться таблица с датами нерабочих дней (содержимое таблицы хорошо видно, если щёлкнуть мышью в фон ячейки рядом со словом Table):

Вложенные таблицы с данными по каждому году

Останется развернуть содержимое вложенных таблиц, щёлкнув по значку с двойными стрелками в шапке столбца Даты (галочку Использовать исходное имя столбца как префикс при этом можно снять):

Разворачиваем вложенные таблицы

… и после нажатия на ОК мы получим то, что хотели — список всех праздников с 2013 и до текущего года:

Все загруженные даты праздников за все годы

Первый, ненужный уже столбец, можно удалить, а для второго задать тип данных Дата (Date) в выпадающем списке в шапке столбца:

Задаем тип данных даты

Сам запрос можно переименовать как-нибудь более осмысленно, чем Запрос1 и выгрузить затем результаты на лист в виде динамической «умной» таблицы с помощью команды Закрыть и загрузить на вкладке Главная (Home — Close & Load):

Готовый производственный календарь в Excel

Обновлять созданный календарь в будущем можно щелчком правой кнопки мыши по таблице или запросу в правой панели через команду Обновить. Или же использовать кнопку Обновить все на вкладке Данные (Date — Refresh All) или сочетание клавиш Ctrl+Alt+F5.

Вот и всё.

Теперь вам больше никогда не нужно тратить время и мыслетопливо на поиски и актуализацию списка праздничных дней — теперь у вас есть «вечный» производственный календарь. Во всяком случае, до тех пор, пока авторы сайта http://xmlcalendar.ru/ поддерживают своё детище, что, я надеюсь, будет ещё очень и очень долго (спасибо им еще раз!).

Ссылки по теме

  • Импорт курса биткойна в Excel из интернета через Power Query
  • Поиск ближайшего рабочего дня функцией РАБДЕНЬ (WORKDAY)
  • Поиск пересечения интервалов дат

04.01.2023

Другие года: 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016.

Согласно статье 112 Трудового кодекса Российской Федерации (в ред. ФЗ № 35-ФЗ от 23 апреля 2012 года) нерабочими праздничными днями в Российской Федерации являются:

Праздники в 2023 году:
✅ 31 декабря 2022 года — выходной день.
✅ 1, 2, 3, 4, 5, 6 и 8 января — Новый год (новогодние каникулы);
✅ 7 января — Рождество Христово;
✅ 23 февраля — День защитника Отечества;
✅ 8 марта — Международный женский день;
✅ 1 мая — Праздник Весны и Труда;
✅ 9 мая — День Победы;
✅ 12 июня — День России;
✅ 4 ноября — День народного единства.

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

Согласно Постановлению Правительства РФ от 29.08.2022 № 1505 «О переносе выходных дней в 2023 году» (ссылка) разработан перенос выходных дней в 2023 году с праздничных дней:
• с 01.01 (воскресенье) на 24.02 (пятница);
• с 08.01 (воскресенье) на 08.09 (понедельник);
Предпраздничные дни в 2023 году:
• вторник 22 февраля, вторник 7 марта, пятница 3 ноября.
Итого 3 предпраздничных дня в 2023 году.

Скачать Производственный календарь 2023 в excel (xls, таблица «Норма времени» на 2 странице)

Согласно статье 112 Трудового кодекса РФ при совпадении выходного и нерабочего праздничного дней выходной день переносится на следующий после праздничного рабочий день. Исключение составляют выходные дни, совпадающие с нерабочими праздничными днями января. Изменениями, внесенными в ст. 112 ТК РФ Федеральным законом от 23.04.2012 № 35-ФЗ, предусматривается, что Правительство Российской Федерации вправе переносить два выходных дня из числа выходных дней, совпадающих с нерабочими январскими праздничными днями, на другие дни в очередном календарном году.

Норма рабочего времени в 2023 году

Период Д кален
дарных
Д рабочих Д выход,
празд.
Д пред-
празд.
Часы 40-
часовая
Часы 36-
часовая
Часы 24-
часовая
Январь 31 17 14 0 136,0 122,4 81,6
Февраль 28 18 10 1 143,0 128,6 85,4
Март 31 22 9 1 175,0 157,4 104,6
1 квартал 90 57 33 2 454,0 408,4 271,6
Апрель 30 20 10 0 160,0 144,0 96,0
Май 31 20 11 0 160,0 144,0 96,0
Июнь 30 21 9 0 168,0 151,2 100,8
2 квартал 91 61 30 0 488,0 439,2 292,8
1 полугодие 181 118 63 2 942,0 847,6 564,4
Июль 31 21 10 0 168,0 151,2 100,8
Август 31 23 8 0 184,0 165,6 110,4
Сентябрь 30 21 9 0 168,0 151,2 100,8
3 квартал 92 65 27 0 520,0 468,0 312,0
Октябрь 31 22 9 0 176,0 158,4 105,6
Ноябрь 30 21 9 1 167,0 150,2 99,8
Декабрь 31 21 10 0 168,0 151,2 100,8
4 квартал 92 64 28 1 511,0 459,8 306,2
2 полугодие 184 129 55 1 1 031,0 927,8 618,2
Год 365 247 118 3 1 973,0 1 775,4 1 182,6

Согласно статье 91 ТК РФ (в ред. Федерального закона от 22 июля 2008 г. N 157-ФЗ) Порядок исчисления нормы рабочего времени на определенные календарные периоды (месяц, квартал, год) в зависимости от установленной продолжительности рабочего времени в неделю определяется федеральным органом исполнительной власти, осуществляющим функции по выработке государственной политики и нормативно-правовому регулированию в сфере труда.» (Собрание законодательства Российской Федерации, 2008, N 30 (ч. I), ст. 3613).

В настоящее время действует Порядок исчисления нормы рабочего времени на определенные календарные периоды времени (месяц, квартал, год) в зависимости от установленной продолжительности рабочего времени в неделю, утвержденный приказом Минздравсоцразвития России от 13 августа 2009 г. N 588н (Бюллетень трудового и социального законодательства РФ, 2009, N 10).
Согласно установленному Порядку исчисления нормы рабочего времени данная норма исчисляется по расчетному графику пятидневной рабочей недели с двумя выходными днями в субботу и воскресенье, исходя из продолжительности ежедневной работы (смены), например, при 40-часовой рабочей неделе — 8 часов, при продолжительности рабочей недели 36 часов она составит 7,2 часа; при 24-часовой рабочей неделе — 4,8 часа. Продолжительность рабочего дня или смены, непосредственно предшествующих нерабочему праздничному дню, уменьшается на один час.
Рассчитанная в приведенном порядке норма рабочего времени распространяется на все режимы труда и отдыха.

Итого
Всего в 2023 году 365 дней (не високосный год) при пятидневной рабочей неделе с двумя выходными днями; 247 рабочих дня, в том числе 3 предпраздничных дня (сокращенных на один час рабочих дней) и 118 выходных и праздничных дней.

Норма рабочего времени в 2023 году составляет:
при 40-часовой рабочей неделе — 1 973,0 часа = 8,0 час. x 247 дней — 3 часа;
при 36-часовой рабочей неделе — 1 775,4 часа = 7,2 час. x 247 дней — 3 часа;
при 24-часовой рабочей неделе — 1 182,6 часа = 4,8 час. x 247 дней — 3 часа.

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

Теперь разберём, как загрузить в Excel производственный календарь для последующего использования. В статье показан один из вариантов, далеко не единственный. 
В качестве источника данных воспользуемся набором на Портале открытых данных РФ (

https://data.gov.ru/opendata/7708660670-proizvcalendar). 
Раскроем паспорт набора:
Набор представляет собой производственный календарь c 1999 до 2025 года. Звездочкой (*) отмечены предпраздничные (сокращенные) дни. Плюсом (+) отмечены перенесенные выходные дни. 
Для загрузки в Excel скопируем ссылку на набор (https://data.gov.ru/opendata/7708660670-proizvcalendar/data-20191112T1252-structure-20191112T1247.csv): 
Запустим Excel. Воспользуемся коннектором для получения данных с Web-страницы (вкладка “Данные” — “Создать запрос” — “Из других запросов” — “Из Интернета”):
В открывшемся диалоге вставим скопированную ранее ссылку на набор:

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


Загруженный набор данных в каждой строке хранит описание для одного года — сначала на каждый месяц — через запятую список дней (выходных, сокращённых и дополнительных выходных), затем несколько статистических столбцов.
Удалим статистические столбцы. Они нам не пригодятся. Наша цель — таблица, где на каждую дату будет признак — рабочий, выходной или сокращённый рабочий (последний вариант — опциональный, такие дни можно тоже интерпретировать как рабочие, в зависимости от задачи):
Итого, у нас осталось 13 колонок — колонка с годом и с каждый месяцем. Развернём колонки с месяцами в плоский список. Для этого воспользуемся командой “Отменить свёртывание столбцов”:
Команда “Отменить свёртывание столбцов” создаёт пары для каждого сочетания названия столбца и ячейки в этом столбце и превращает их в столбцы:
Далее разделим столбец с днями на отдельные столбцы с помощью команды ”Разделить столбец” — “По разделителю”:
В качестве разделителя укажем запятую, разделим по каждому вхождения разделителя:
Получим 16 столбцов с числами — столько, сколько их значится в максимуме в некоторых месяцах. Там, где значений в ячейке было менее 16 — лишние столбцы остались со значением null. Произведём с числами ту же операцию, которую произвели с месяцами — развернём в плоский список с помощью команды “Отменить свёртывание столбцов”:
И получим таблицу, где каждая строка — характеристики одной даты. Столбец “Атрибут.1” появился как порядковый номер конкретного числа в ячейке, он не пригодится. Удалим его:
Теперь мы можем обработать звёздочки и плюсики, присвоив каждой строке (= каждой дате) некоторый признак. Чтобы далее использовать вычисление, определяющее вхождение символов * или + в строку — нам необходимо преобразовать столбец в текст:
Далее добавляем условный столбец, который будет присваивать признак каждому дню в зависимости от вхождения * и +:
Пропишем условие определения признака следующим образом: если в значении дня (столбец “Значение”) присутствует символ *, то считаем такой день сокращённым рабочим, иначе — выходным. Мы могли бы добавить ещё одно условие для вхождения символа +, но такие дни тоже являются выходными, хоть и добавленными. Можно выделить это тип дней отдельно, если этого требует задача. Мы выделять не будем:
Получаем вот такой столбец:
Теперь можно избавить из дополнительных символов у числа (* и +), чтобы перейти к дальнейшим шагам обработки. Для удаления символов воспользуемся командой “Замена значений”:
Заменим звёздочку на “ничего”. Оставим поле с итоговым значением пустым. Это будет равносильно тому, чтобы удалить выбранные подстроки (в данном случае — звёздочки):
Проделаем аналогичную операцию для удаления плюсиков. Теперь у нас есть три столбца — части даты. Соберём их в дату с помощью вычисляемого столбца:
Сбор даты из элементов можно произвести несколько способами. Рассмотрим один  из вариантов — соберём все элементы даты в текстовую строку и преобразуем в дату. Date.From — преобразовывает текст в дату. Text.Combine — объединяет несколько текстовых строк в одну. Text.From — преобразуем нетекстовое значение к текст. Точки между элементами даты добавим для разделения (можно воспользоваться другим символом, например, тире):

Date.From(

    Text.Combine(

        {

            [Значение], 

            «.», 

            [Атрибут], 

            «.», 

            Text.From([#»Год/Месяц»])

        }

    )

)


В результате получим столбец с датой — Date. Теперь можем удалить составные столбцы — они свою роль сыграли:
Осталось скорректировать типы данных. Поставить, что столбец Date — это данные типа Дата, Day type — Текст:
Результат:
Итоговый код обработки данных:

let

    Источник = Csv.Document(Web.Contents(«https://data.gov.ru/opendata/7708660670-proizvcalendar/data-20191112T1252-structure-20191112T1247.csv»),[Delimiter=»,», Columns=18, Encoding=65001, QuoteStyle=QuoteStyle.None]),

    #»Повышенные заголовки» = Table.PromoteHeaders(Источник, [PromoteAllScalars=true]),

    #»Измененный тип» = Table.TransformColumnTypes(#»Повышенные заголовки»,{{«Год/Месяц», Int64.Type}, {«Январь», type text}, {«Февраль», type text}, {«Март», type text}, {«Апрель», type text}, {«Май», type text}, {«Июнь», type text}, {«Июль», type text}, {«Август», type text}, {«Сентябрь», type text}, {«Октябрь», type text}, {«Ноябрь», type text}, {«Декабрь», type text}, {«Всего рабочих дней», Int64.Type}, {«Всего праздничных и выходных дней», Int64.Type}, {«Количество рабочих часов при 40-часовой рабочей неделе», Int64.Type}, {«Количество рабочих часов при 36-часовой рабочей неделе», type text}, {«Количество рабочих часов при 24-часовой рабочей неделе», type text}}),

    #»Удаленные столбцы» = Table.RemoveColumns(#»Измененный тип»,{«Всего рабочих дней», «Всего праздничных и выходных дней», «Количество рабочих часов при 40-часовой рабочей неделе», «Количество рабочих часов при 36-часовой рабочей неделе», «Количество рабочих часов при 24-часовой рабочей неделе»}),

    #»Несвернутые столбцы» = Table.UnpivotOtherColumns(#»Удаленные столбцы», {«Год/Месяц»}, «Атрибут», «Значение»),

    #»Разделить столбец по разделителю» = Table.SplitColumn(#»Несвернутые столбцы», «Значение», Splitter.SplitTextByDelimiter(«,», QuoteStyle.Csv), {«Значение.1», «Значение.2», «Значение.3», «Значение.4», «Значение.5», «Значение.6», «Значение.7», «Значение.8», «Значение.9», «Значение.10», «Значение.11», «Значение.12», «Значение.13», «Значение.14», «Значение.15», «Значение.16»}),

    #»Измененный тип1″ = Table.TransformColumnTypes(#»Разделить столбец по разделителю»,{{«Значение.1», type text}, {«Значение.2», type text}, {«Значение.3», type text}, {«Значение.4», type text}, {«Значение.5», type text}, {«Значение.6», type text}, {«Значение.7», type text}, {«Значение.8», type text}, {«Значение.9», type text}, {«Значение.10», type text}, {«Значение.11», type text}, {«Значение.12», type text}, {«Значение.13», Int64.Type}, {«Значение.14», Int64.Type}, {«Значение.15», Int64.Type}, {«Значение.16», Int64.Type}}),

    #»Несвернутые столбцы1″ = Table.UnpivotOtherColumns(#»Измененный тип1″, {«Год/Месяц», «Атрибут»}, «Атрибут.1», «Значение»),

    #»Удаленные столбцы1″ = Table.RemoveColumns(#»Несвернутые столбцы1″,{«Атрибут.1»}),

    #»Измененный тип2″ = Table.TransformColumnTypes(#»Удаленные столбцы1″,{{«Значение», type text}}),

    #»Условный столбец добавлен» = Table.AddColumn(#»Измененный тип2″, «Date type», each if Text.Contains([Значение], «*») then «Сокращённый рабочий» else «Выходной»),

    #»Замененное значение» = Table.ReplaceValue(#»Условный столбец добавлен»,»*»,»»,Replacer.ReplaceText,{«Значение»}),

    #»Замененное значение1″ = Table.ReplaceValue(#»Замененное значение»,»+»,»»,Replacer.ReplaceText,{«Значение»}),

    #»Добавлен пользовательский объект» = Table.AddColumn(#»Замененное значение1″, «Date», each Date.From(

    Text.Combine(

        {

            [Значение],

            «.», 

            [Атрибут], 

            «.», 

            Text.From([#»Год/Месяц»])

        }

    )

)),

    #»Удаленные столбцы2″ = Table.RemoveColumns(#»Добавлен пользовательский объект»,{«Год/Месяц», «Атрибут», «Значение»}),

    #»Измененный тип3″ = Table.TransformColumnTypes(#»Удаленные столбцы2″,{{«Date type», type text}})

in

    #»Измененный тип3″

*****

Получили почти то, что хотели, за исключением одного “но” — в итоговой таблице нет рабочих дней. Для решения некоторых задач полученного результата вполне достаточно. Кроме того, обработку дней мы можем далее заложить логикой (а-ля “Всё, что не в таблице — рабочие дни”). Но — закончим задачу для полноценного календаря, где тип присвоен каждой дате. Для этого сгенерим таблицу с полным список дат и объединим с полученной. Для генерации списка дат создадим пустой запрос:
И отредактируем код запроса вручную в Расширенном редакторе:
Зададим границы диапазона данных — дату начала и дату окончания:

date_start = #date(2015, 1, 1),
date_end = #date(2023, 1, 1),

Воспользуемся List.Dates для генерации списка дат. Ей необходимо три параметра: дата старта диапазона, количество элементов и шаг:

date_list = List.Dates(

                                date_start,                                 

                                Duration.Days(date_end — date_start) + 1,                               

                                #duration(1, 0, 0, 0)    

)

Получим вот такой код:

let

     date_start = #date(2015, 1, 1),

     date_end = #date(2023, 1, 1),

     date_list = List.Dates(

                                     date_start,

                                     Duration.Days(date_end — date_start) + 1,

                                     #duration(1, 0, 0, 0)

)

in

     date_list 


И в результате получим вот список дат в заданном диапазоне. Это список (не таблица) и, соответственно, не имеет всех атрибутов таблицы. Преобразуем его в таблицу:
А вот это уже таблица. Переименуем, изменим типа данных на Date:
Получаем таблицу со списком дат, но без указания типов этих дат. “Вытащим” типы данных из первой созданной таблицы. Для этого объединим таблицы:
Если мы вызвали команду объединения, находясь во второй таблице, то эта вторая таблица автоматически встанет в качестве первой объединяемой таблицы. Нам нужно выбрать вторую — это данные, загруженные с Портала открытых данных. Необходимо указать, по каким столбцам сопоставлять данные — выбираем в обеих таблицах колонку Date:
Для каждой строки создалась подтаблица из данных присоединённой таблицы. Развернём колонки:
Снимем галочку использования названия таблицы в качестве префикса, снимем галочку со столбца Date:
В результате получим таблицу, у которой будут проставлены типы дат у выходных и  сокращённых рабочих дней. У части дат будет null вместо типа даты. Исходя из логики загруженного производственного календаря делаем вывод, что это простые рабочие дни. Заменим null на слово “Рабочий”:
Вот теперь — всё. Осталось только загрузить :)
Итоговый код второго запроса:

let

    date_start = #date(2015, 1, 1),

    date_end = #date(2023, 1, 1),

    date_list = List.Dates(

                        date_start,                                    

                        Duration.Days(date_end — date_start) + 1,      

                        #duration(1, 0, 0, 0)                        

    ),

    #»Преобразовано в таблицу» = Table.FromList(date_list, Splitter.SplitByNothing(), null, null, ExtraValues.Error),

    #»Переименованные столбцы» = Table.RenameColumns(#»Преобразовано в таблицу»,{{«Column1», «Date»}}),

    #»Измененный тип» = Table.TransformColumnTypes(#»Переименованные столбцы»,{{«Date», type date}}),

    #»Объединенные запросы» = Table.NestedJoin(#»Измененный тип», {«Date»}, #»data-20191112T1252-structure-20191112T1247″, {«Date»}, «data-20191112T1252-structure-20191112T1247», JoinKind.LeftOuter),

    #»Развернутый элемент data-20191112T1252-structure-20191112T1247″ = Table.ExpandTableColumn(#»Объединенные запросы», «data-20191112T1252-structure-20191112T1247», {«Date type»}, {«Date type»}),

    #»Замененное значение» = Table.ReplaceValue(#»Развернутый элемент data-20191112T1252-structure-20191112T1247″,null,»Рабочий»,Replacer.ReplaceValue,{«Date type»})

in

    #»Замененное значение»

Подробная инструкция так же в видео.

В одном из заказов недавно столкнулся с проблемой получения праздничных дней согласно утвержденному производственному календарю. Да, я знаю, что в компаниях он может быть свой, отличный от опубликованного государством. И смысла как-то получать список праздничных дат с общедоступных порталов не было. Но вот именно сейчас потребовался именно общедоступный опубликованный календарь, чтобы можно было его автоматом скачать и применить. И оказалось, что это тоже не самая простая задача: многие календари в сети либо в формате PDF, либо в виде frame-ов по месяцам, либо вообще картинками. Только на одном сайте получилось найти файл для скачивания: https://data.gov.ru/opendata/7708660670-proizvcalendar. Но и там оказалась не сразу ссылка на готовый календарь, а описание набора, потом паспорт и уже только в паспорте набора можно найти ссылку на файл:
Ссылка на производственный календарь
эта ссылка нам и нужна. И тут две проблемы:

Для рабочего проекта я выбрал способ получения дат через VBA(для поддержки всех версий независимо от надстроек), но в связи с популярностью Power Qwery решил сделать решение и при помощи этой надстройки.

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

'---------------------------------------------------------------------------------------
' Author : Дмитрий (The_Prist) Щербаков
'          Профессиональная разработка приложений для MS Office любой сложности
'          Проведение тренингов по MS Excel
'          https://www.excel-vba.ru
'          info@excel-vba.ru
'          WebMoney - R298726502453; Яндекс.Деньги - 41001332272872
' Purpose: Загрузка праздничных дат из производственного календаря с сайта data.gov.ru
'          https://www.excel-vba.ru/chto-umeet-excel/proizvodstvennyj-kalendar-v-excel-vba-i-power-qwery/
'---------------------------------------------------------------------------------------
Option Explicit
'объявление функции API - URLDownloadToFile для скачивания файла
'Идет в самом начале, т.к. API функции необходимо объявлять именно здесь
'   работает на любых ПК под управлением ОС Windows
'   на MAC код работать не будет
#If Win64 Then 'для операционных систем с 64-разрядной архитектурой
    Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
            (ByVal pCaller As LongLong, ByVal szURL As String, ByVal szFileName As String, _
             ByVal dwReserved As LongLong, ByVal lpfnCB As LongLong) As LongLong
#Else
    #If VBA7 Then 'для любых операционных систем с офисом 2010 и выше
        Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
            (ByVal pCaller As LongPtr, ByVal szURL As String, ByVal szFileName As String, _
                ByVal dwReserved As Long, ByVal lpfnCB As LongPtr) As LongPtr
    #Else 'для 32-разрядных операционных систем
        Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                                        (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, _
                                        ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
    #End If
#End If
 
'Основная процедура поиска ссылки и скачивания календаря
'    в ходе работы использует остальные функции
Sub LoadCalendar()
    Dim res, response$, surl$, sex$, sFName$, sMsg$
    Dim oXMLHTTP As Object
    Dim lp&, le&, le2&
    Dim wbPrCalendar As Workbook
 
    Application.ScreenUpdating = False
    Err.Clear
    On Error GoTo err_handler
    'подключаемся к сайту
    Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
    With oXMLHTTP
        .Open "GET", "https://data.gov.ru/opendata/7708660670-proizvcalendar", False
        .send
        'ждем пока страница прогрузится
        Do While .readyState <> 4
          DoEvents
        Loop
        'запоминаем исходный код страницы(для поиска ссылки)
        response = .responseText
    End With
    If Len(response) Then
        'ищем место с ссылкой на наш CSV
        '   их там несколько, нам нужна "Гиперссылка (URL) на набор"
        lp = InStr(1, response, "Гиперссылка (URL) на набор", 1)
        If lp > 0 Then
            'если нашли - ищем начало гиперссылки для скачивания(по ключевым http)
            le = InStr(lp, response, "http", 1)
            If le > 0 Then
                'если это CSV - берем его
                le2 = InStr(le, response, ".csv", 1)
                'CSV не нашли - пробуем найти xlsx(что вряд ли, но лушче попробовать)
                If le2 = 0 Then
                    le2 = InStr(le, response, ".xls", 1)
                End If
                If le2 > 0 Then
                    'формируем только адрес ссылки для скачивания
                    lp = InStr(le2, response, Chr(34), 1)
                    surl = Mid(response, le, lp - le)
                    lp = InStrRev(surl, ".")
                    sex = Mid(surl, lp, Len(surl) - lp + 1)
                    'пробуем скачать при помощи функции API
                    Set wbPrCalendar = CallDownload(surl, "prod_cal" & sex)
                    'обрабатываем скачанный файл
                    If Not wbPrCalendar Is Nothing Then
                        wbPrCalendar.Activate
                        sFName = wbPrCalendar.FullName
                        'преобразуем данные в файле в столбец дат
                        Call FillProdCalend(wbPrCalendar)
                        wbPrCalendar.Close 0
                        DoEvents
                        On Error Resume Next
                        'удаляем после обработки
                        Kill sFName
                        Err.Clear
                        DoEvents
                        sMsg = "Производственный календарь успешно обновлен"
                    End If
                End If
            End If
        End If
    End If
'если будет какая-то ошибка - код перейдет сюда и покажет текст ошибки
err_handler:
    If Err.Number <> 0 Then
        sMsg = "Не удалось обновить Производственный календарь." & vbNewLine & _
               "Ошибка: " & Err.Description
    End If
    Application.ScreenUpdating = True
    MsgBox sMsg, vbInformation, "www.excel-vba.ru"
End Sub
 
'---------------------------------------------------------------------------------------
' File   : mDownloadFileFromURL
' Purpose: код позволяет скачивать файлы из интернета по указанной ссылке
'          https://www.excel-vba.ru/chto-umeet-excel/kak-skachat-fajl-iz-interneta-po-ssylke/
'---------------------------------------------------------------------------------------
Function CallDownload(sFileURL As String, sFileName As String) As Workbook
    'переменная для хранения пути к папке
    Dim sFilePath As String, ToPathName As String
    Dim h
 
    sFilePath = Environ("temp")
    If Right(sFilePath, 1) <> "" Then sFilePath = sFilePath & ""
    ToPathName = sFilePath & sFileName
    'проверяем есть ли файл с таким же именем в выбранной папке
    If Dir(ToPathName, 16) <> "" Then
        On Error Resume Next
        Kill ToPathName
        DoEvents
        On Error GoTo 0
    End If
    'если не возникло ошибок при удалении файла - скачиваем его по ссылке
    '   если ошибка была - значит такой файл уже открыт
    '   и в дальнейшем все равно получим ошибку
    If Err.Number = 0 Then
        'вызов функции API для непосредственно скачивания
        h = (URLDownloadToFile(0, sFileURL, ToPathName, 0, 0) = 0)
        'если h = False - файл не удалось скачать, показываем инф.окно
        If h = False Then
            MsgBox "Невозможно скачать файл." & vbNewLine & _
                    "Возможно, у Вас нет прав на создание файлов в папке '" & sFilePath & "'.", _
                    vbInformation, "www.excel-vba.ru"
                    Set CallDownload = Nothing
                    Exit Function
        Else 'файл успешно скачан
            If IsBookOpen(sFileName) Then
                MsgBox "Файл с именем '" & sFileName & "' уже открыт. Закройте открытый файл и повторите попытку.", vbCritical, "www.excel-vba.ru"
            Else
                Set CallDownload = Application.Workbooks.Open(ToPathName)
            End If
        End If
    Else
        Set CallDownload = Nothing
    End If
End Function
'функция заполнения листа "ProdCalend" датами из производственного календаря
'   предварительно функция разбивает даты на отдельные
'   т.к. изначально они записаны в виде перечня дней для каждого месяца
Function FillProdCalend(wbCSV As Workbook)
    Dim acsv, ares()
    Dim dic As Object
    Dim llastr&, lr&, lc&, lcnt&
    Dim ly&, lm&, ld&
    Dim asp, sd$, s$, x
    Dim dt As Date
 
    With wbCSV.Worksheets(1)
        llastr = .Cells(.Rows.Count, 1).End(xlUp).Row
        acsv = .Cells(1, 1).Resize(llastr, 13).Value
    End With
    With ThisWorkbook.Sheets("ProdCalend")
        'очищаем лист от старых данных
        .Columns(1).Cells.Clear
        'здесь будем хранить список уникальных дат
        Set dic = CreateObject("scripting.dictionary")
        dic.comparemode = 1
        'просматриваем каждую строку файла(год), начиная со 2-й
        For lr = 2 To UBound(acsv, 1)
            If IsNumeric(acsv(lr, 1)) Then
                ly = Val(Trim(acsv(lr, 1)))
                'просматриваем каждый столбец файла(месяц), начиная со 2-го
                For lc = 2 To UBound(acsv, 2)
                    lm = lc - 1
                    s = acsv(lr, lc)
                    s = Trim(s)
                    'убираем символы +
                    'которыми обозначаются перенесенные праздничные дни
                    s = Replace(s, "+", "")
                    If Len(s) Then
                        'разбиваем единую строку вида 1,2,3,4,6*,7,9,10,16,17,23,24,30,31
                        'на отдельные дни
                        asp = Split(s, ",")
                        'перебор каждого дня и создание из него даты
                        'с запоминанием в словарь дат dic
                        For Each x In asp
                            s = Trim(x)
                            'не учитываем даты со знаком * - это сокращенные предпраздничные дни
                            If InStr(1, s, "*", 1) = 0 Then
                                If Len(s) Then
                                    ld = Val(s)
                                    dt = DateSerial(ly, lm, ld)
                                    If Not dic.exists(dt) Then
                                        dic.Add dt, 0&
                                    End If
                                End If
                            End If
                        Next
                    End If
                Next
            End If
        Next
        'даты есть - записываем на лист
        '   можно было поступить проще
        '   .Cells(2, 1).Resize(dic.Count).Value = Application.Transpose(dic.Keys)
        '   но этот метод опасен тем, что порой может выгрузить не все данные
        '   хотя в данном конкретном случае это очень маловероятно, т.к. ограничения касаются 
        '   кол-ва строк в 65536 и текста в каждой строке до 255 символов
        If dic.Count > 0 Then
            ReDim ares(1 To dic.Count, 1 To 1)
            lr = 0
            For Each x In dic.keys
                lr = lr + 1
                ares(lr, 1) = x
            Next
            .Cells(1, 1).Value = "Праздники и выходные"
            .Cells(2, 1).Resize(dic.Count).Value = ares
        End If
    End With
End Function
 
'Функция проверки - открыта ли книга с заданным именем
'подробнее:
'        https://www.excel-vba.ru/chto-umeet-excel/kak-proverit-otkryta-li-kniga/
Function IsBookOpen(wbName As String) As Boolean
    Dim wbBook As Workbook
    For Each wbBook In Workbooks
        If Windows(wbBook.Name).Visible Then
            If wbBook.Name = wbName Then IsBookOpen = True: Exit For
        End If
    Next wbBook
End Function

Чтобы использовать код необходимо создать файл Excel, в этом файле создать лист с именем «ProdCalend». Далее переходим в редактор VBA(Alt+F11) —InsertModule. Вставляем туда код выше полностью. Или скачать файл ниже — там уже все сделано удобно и красиво:
Скачать файл с кодом:

В случае с Power Qwery все с одной стороны проще, а с другой есть свои нюансы. Взять хотя бы попытку получить напрямую текст страницы https://data.gov.ru/opendata/7708660670-proizvcalendar: если попытаться подключиться через стандартный метод(Другие(Other)Из интернета(from Web), то придется очень долго разворачивать элемент Document на составные части разметки HTML в поисках тегов DIV и A для определения строки с гиперссылкой. Что на мой взгляд не оптимально и уж совсем не гибко — любое изменение структуры страницы, даже малейшее может привести к ошибке.
Поэтому я использовал менее очевидный, но куда более удобный в данном случае вариант — Lines.FromBinary(Web.Contents(«https://data.gov.ru/opendata/7708660670-proizvcalendar»)). Это самая важная строка в текущей задаче — она получает исходный текст страницы сайта в виде разбитого на строки текста, в котором потом можно будет просматривать и искать нужное нам
Power Qwery FromBinary function
а дальше по сути идет тоже самое, что делалось кодом VBA: ищем в этом тексте ссылку, выдергиваем только ссылку для скачивания файла календаря, подключаемся к этой ссылке для получения конечного CSV и делаем преобразования. Только это выглядит куда проще и заметно короче, чем тоже самое на VBA :) Сам код из расширенного редактора:

let
//получаем исходный текст страницы в виде разбитого на строки текста
    Source = Table.FromColumns({Lines.FromBinary(Web.Contents("https://data.gov.ru/opendata/7708660670-proizvcalendar"))}),
    //отбираем из строк ту, которая содержит внутри текст "Гиперссылка (URL) на набор" и ".csv" и превращаем все это в строку
    //  т.к. изначально Table.SelectRows возвращает набор в виде таблицы
    CsvURLText = Table.SelectRows(Source, each Text.Contains([Column1], "Гиперссылка (URL) на набор") and Text.Contains([Column1], ".csv")){0}[Column1],
    //ищем начало гиперссылки
    url_start_pos = Text.PositionOf(CsvURLText,"http"),
    //ищем конец гиперссылки
    url_end_pos = Text.PositionOf(CsvURLText,".csv"),
    //формируем гиперссылку из CsvURLText
    url = Text.Middle(CsvURLText,url_start_pos,url_end_pos-url_start_pos+4),
    //скачиваем файл CSV по сформированной гиперссылке и открываем его
    //в заголовках будут имена месяцев
    csvfile = Table.PromoteHeaders(Csv.Document(Web.Contents(url),[Delimiter=",", Columns=18, Encoding=65001, QuoteStyle=QuoteStyle.None]), [PromoteAllScalars=true]),
    //сворачиваем столбцы с датами в два столбца: название месяца("Атрибут") и перечень дат("Значение")
    #"Несвернутые столбцы" = Table.UnpivotOtherColumns(csvfile, {"Год/Месяц", "Всего рабочих дней", "Всего праздничных и выходных дней", "Количество рабочих часов при 40-часовой рабочей неделе", "Количество рабочих часов при 36-часовой рабочей неделе", "Количество рабочих часов при 24-часовой рабочей неделе"}, "Атрибут", "Значение"),
    //убираем символы +, которыми обозначаются перенесенные праздничные дни
    #"Замененное значение1" = Table.ReplaceValue(#"Несвернутые столбцы","+","",Replacer.ReplaceText,{"Значение"}),
    //разбиваем столбец с днями на отдельные столбцы
    #"Разделить столбец по разделителю" = Table.SplitColumn(#"Замененное значение1", "Значение", Splitter.SplitTextByDelimiter(",", QuoteStyle.Csv), {"Значение.1", "Значение.2", "Значение.3", "Значение.4", "Значение.5", "Значение.6", "Значение.7", "Значение.8", "Значение.9", "Значение.10", "Значение.11", "Значение.12", "Значение.13", "Значение.14", "Значение.15", "Значение.16"}),
    //сворачиваем все столбцы с днями в два: "Атрибут.1"(нам не нужен) и день("Значение")
    #"Другие столбцы с отмененным свертыванием" = Table.UnpivotOtherColumns(#"Разделить столбец по разделителю", {"Год/Месяц", "Всего рабочих дней", "Всего праздничных и выходных дней", "Количество рабочих часов при 40-часовой рабочей неделе", "Количество рабочих часов при 36-часовой рабочей неделе", "Количество рабочих часов при 24-часовой рабочей неделе", "Атрибут"}, "Атрибут.1", "Значение"),
    //удаляем все строки с сокращенными днями
    #"Строки с примененным фильтром" = Table.SelectRows(#"Другие столбцы с отмененным свертыванием", each not Text.Contains([Значение], "*")),
    //в отдельном столбце формируем из столбцов с годом, месяцем и днем дату
    #"Добавлен пользовательский объект" = Table.AddColumn(#"Строки с примененным фильтром", "Пользовательский", each Date.FromText([Значение] & " " & [Атрибут] & " " & [#"Год/Месяц"],"Ru-ru")),
    //переименовываем столбец
    #"Переименованные столбцы" = Table.RenameColumns(#"Добавлен пользовательский объект",{{"Пользовательский", "Дата"}}),
    //удаляем лишние столбцы(по сути все, кроме столбца дата)
    #"Другие удаленные столбцы" = Table.SelectColumns(#"Переименованные столбцы",{"Дата"}),
    //преобразуем тип Any(Любой) в тип Дата
    #"Измененный тип" = Table.TransformColumnTypes(#"Другие удаленные столбцы",{{"Дата", type date}})
in
    #"Измененный тип"

Так же не стал расписывать со скринами по шагам все преобразования, т.к. каждый желающий может скачать файл(приложен ниже) с запросом PQ и просмотреть по шагам все действия:
Шаги запроса Power Qwery
Но если вдруг это надо будет — пишите в комментариях, постараюсь описать процесс наглядно(в будущем подготовлю видеоурок на данную тему).

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

Из-за “плавающих” выходных и праздничных дней в России мы не можем каждый год использовать один и тот же набор данных.

Лично у меня ежегодно возникает вопрос – где скачать производственный календарь. Желательно в удобном формате Excel и с наименьшими трудозатратами. И вот совсем недавно я нашёл для себя решение, которое, уверен, пригодится многим.

Для автоматизации процесса нам понадобится

  • Microsoft Excel (2010, 2013 или 2016)
  • Страничка на портале Открытых Данных России откуда можно скачать производственный календарь в csv формате: http://data.gov.ru/opendata/7708660670-proizvcalendar.

* для Excel 2010 и 2013 вам понадобится бесплатная надстройка Power Query, скачать можно отсюда.

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


На странице так же доступны предыдущие версии и версия производственного календаря в xlsx:


В Excel 2016 для решения подобных задач у нас есть группа кнопок “Скачать и преобразовать” (Get & Transform) на закладке меню “Данные” (Data).


Для Excel 2010 и Excel 2013 такой же функционал доступен в виде бесплатной надстройки Power Query, можно скачать отсюда. Функционал надстройки развивается каждый месяц, я рекомендую регулярно обновляться, чтобы всегда иметь под рукой новейшие функции и возможности трансформации данных.

Когда все нужные программы установлены и источник информации исследован – вернемся к задаче.

Для скачивания чего-либо из Интернета нам нужна ссылка на файл или страницу.

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

Паспорт содержит важную информацию о наборе, из которой, в частности, мы можем взять “Гиперссылку (URL) на набор данных”


Скопируем URL и сделаем запрос “Из интернета”.


Вставляем ссылку на csv файл


Далее – выберем кодировку 65001 UTF-8, игнорируем авто-определение типов данных и жмём “Изменить”


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

  • Используем первую строку в качестве заголовков столбцов


  • Выберем нужные нам столбцы. Воспользуемся функцией “Выбор столбцов” (Select Columns)



  • Для удобства фильтрации изменим формат столбца “Год/Месяц” на “Целое число”


  • Воспользуемся фильтром, оставим только интересующие нас годы


Зададим фильтр с нужными нам условиями


  • Переименуем столбцы в порядковые номера месяцев и “Год/Месяц” в “Год”


  • Далее воспользуемся функцией “Отменить свёртывание других столбцов” (Unpivot Other Columns) доступной на закладке меню “Преобразование” (Transform), выделив предварительно столбец “Год”


  • Теперь выделим столбец “Значение” и разделим его на столбцы по разделителю “запятая”.


Это действие превращает таблицу в нечто ужасное с кучей столбцов. К тому же возникает непрошенный шаг – “Измененный тип1”, который нужно удалить.


Чтобы привести таблицу в нормальный вид, еще раз воспользуемся функцией “Отменить свертывание других столбцов” (Unpivot Other Columns)

  • Выделяем столбцы “Год” и “Атрибут” (далее его переименуем в месяц)


В результате получается таблица


  • Удаляем столбец “Атрибут.1” образованный из заголовков столбцов


  • Среди значений выходных и праздничных дней опубликованный календарь содержит предпраздничные дни. В некоторых сценариях их важно учитывать, так как в эти дни количество рабочих часов сокращено.

    Но если интерес представляют только нерабочие дни, то дни со звёздочкой нужно исключить из списка. Это можно сделать простым фильтром “не содержит” символ “*”


  • Осталась пара штрихов – переименовать столбцы и установить корректный тип данных


  • В заключение можно добавить столбец с датой


Используем формулу


  • Получив столбец с датой, можно убрать предыдущие столбцы


  • Важно установить корректный тип данных!


  • Осталось сохранить запрос и можно выводить его на лист


Подобным запросом мы получаем не полный список календарных дат, так как публикуемый на портале Открытых Данных набор содержит только праздничные и предпраздничные дни.

Полученный список может быть использован в функциях РАБДЕНЬ (WORKDAY), РАБДЕНЬ.МЕЖД (WORKDAY.INTL), а также для разметки полного календаря рабочими / не рабочими днями (что актуально для моделей в Power Pivot и Power BI).

Как обращаться к наиболее актуальному набору данных

Благодаря тому, что есть HTML представление паспорта данных на странице http://data.gov.ru/node/19107/code-passport

к нему тоже можно сделать запрос из Power Query (“Скачать и Преобразовать” / Get & Transform)

Интерес представляет блок со словами “Гиперссылка (URL) на набор”. Именно эта строка содержит ссылку на наиболее актуальный набор.


Разобраться, как это работает, вы можете, изучив xlsx-файл доступный по ссылке.

В нём вы найдёте несколько запросов


Для упрощения жизни разработчиков моделей в Power Pivot и Power BI, запрос на получение списка выходных дней доступен в виде функции в моей коллекции функций на Github – List.Dates.HolidaysRU

Если вы знаете, где можно найти такую же официальную информацию для СНГ стран, в частности, Казахстана, Украины и Республики Беларусь, оставьте комментарий со ссылкой. А ещё лучше – pull request в проект с соответствующими функциями.

Like this post? Please share to your friends:
  • Производственный календарь 2017 скачать в excel
  • Производственный календарь 2016 excel
  • Производственные календари в excel
  • Производственная характеристика образец word
  • Произошла исключительная ситуация microsoft word метод или свойство недоступны поскольку эту команду