title | keywords | f1_keywords | ms.prod | api_name | ms.assetid | ms.date | ms.localizationpriority |
---|---|---|---|---|---|---|---|
WorksheetFunction.WorkDay method (Excel) |
vbaxl10.chm137347 |
vbaxl10.chm137347 |
excel |
Excel.WorksheetFunction.WorkDay |
358c358f-c76e-1309-4a2f-8e50f8d7e7d9 |
05/25/2019 |
medium |
WorksheetFunction.WorkDay method (Excel)
Returns a number that represents a date that is the indicated number of working days before or after a date (the starting date). Working days exclude weekends and any dates identified as holidays. Use WorkDay to exclude weekends or holidays when you calculate invoice due dates, expected delivery times, or the number of days of work performed.
Syntax
expression.WorkDay (Arg1, Arg2, Arg3)
expression A variable that represents a WorksheetFunction object.
Parameters
Name | Required/Optional | Data type | Description |
---|---|---|---|
Arg1 | Required | Variant | Start_date — a date that represents the start date. |
Arg2 | Required | Variant | Days — the number of nonweekend and nonholiday days before or after start_date. A positive value for days yields a future date; a negative value yields a past date. |
Arg3 | Optional | Variant | Holidays — an optional list of one or more dates to exclude from the working calendar, such as state and federal holidays and floating holidays. The list can be either a range of cells that contain the dates or an array constant of the serial numbers that represent the dates. |
Return value
Double
Remarks
[!IMPORTANT]
Dates should be entered by using the DATE function, or as results of other formulas or functions. For example, use DATE(2008,5,23) for the 23rd day of May, 2008. Problems can occur if dates are entered as text .
Microsoft Excel stores dates as sequential serial numbers so they can be used in calculations. By default, January 1, 1900 is serial number 1, and January 1, 2008 is serial number 39448 because it is 39,448 days after January 1, 1900. Microsoft Excel for the Macintosh uses a different date system as its default.
[!NOTE]
Visual Basic for Applications (VBA) calculates serial dates differently than Excel. In VBA, serial number 1 is December 31, 1899, rather than January 1, 1900.
If any argument is not a valid date, WorkDay returns the #VALUE! error value.
If start_date plus days yields an invalid date, WorkDay returns the #NUM! error value.
If days is not an integer, it is truncated.
[!includeSupport and feedback]
Содержание
- Метод WorksheetFunction.WorkDay (Excel)
- Синтаксис
- Параметры
- Возвращаемое значение
- Замечания
- Поддержка и обратная связь
- метод WorksheetFunction.WorkDay_Intl (Excel)
- Синтаксис
- Параметры
- Возвращаемое значение
- Замечания
- Поддержка и обратная связь
- Функция Weekday
- Синтаксис
- Settings
- Возвращаемые значения
- Замечания
- Пример
- См. также
- Поддержка и обратная связь
- VBA Excel. Расчет рабочего времени
- Календарь рабочего времени
- Заполнение строки часов
- Name already in use
- VBA-Docs / api / Excel.WorksheetFunction.WorkDay.md
Метод WorksheetFunction.WorkDay (Excel)
Возвращает число, представляющее дату, представляющую указанное число рабочих дней до или после даты (начальной даты). Рабочие дни исключают выходные и любые даты, определенные как праздники. Используйте WorkDay , чтобы исключить выходные или праздничные дни при расчете сроков выполнения счета, ожидаемого времени доставки или количества выполненных работ.
Синтаксис
expression. WorkDay (Arg1, Arg2, Arg3)
Выражение Переменная, представляющая объект WorksheetFunction .
Параметры
Имя | Обязательный или необязательный | Тип данных | Описание |
---|---|---|---|
Arg1 | Обязательный | Variant | Start_date — дата, представляющая дату начала. |
Arg2 | Обязательный | Variant | Days — количество ненедельных и ненедельных дней до или после start_date. Положительное значение для дней дает дату в будущем; отрицательное значение возвращает прошлую дату. |
Arg3 | Необязательный | Variant | Праздники — необязательный список одной или нескольких дат для исключения из рабочего календаря, например государственных и федеральных праздников и плавающих праздников. Список может быть диапазоном ячеек, содержащих даты, или константой массива серийных номеров, представляющих даты. |
Возвращаемое значение
Double
Замечания
Даты следует вводить с помощью функции DATE или в качестве результатов других формул или функций. Например, используйте date(2008,5;23) для 23-го дня мая 2008 г. Проблемы могут возникнуть, если даты вводятся в виде текста .
Microsoft Excel сохраняет даты как последовательные серийные номера, чтобы их можно было использовать в вычислениях. По умолчанию 1 января 1900 года — серийный номер 1, а 1 января 2008 года — серийный номер 39448, так как после 1 января 1900 г. это 39 448 дней. Microsoft Excel для Macintosh использует другую систему даты по умолчанию.
Visual Basic для приложений (VBA) вычисляет последовательные даты иначе, чем Excel. В VBA серийный номер 1 — 31 декабря 1899 года, а не 1 января 1900 года.
Если какой-либо аргумент не является допустимой датой, WorkDay возвращает #VALUE! значение ошибки.
Если start_date плюс дни возвращает недопустимую дату, WorkDay возвращает #NUM! значение ошибки.
Если число дней не является целым числом, оно усекается.
Поддержка и обратная связь
Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.
Источник
метод WorksheetFunction.WorkDay_Intl (Excel)
Возвращает серийный номер даты до или после указанного количества рабочих дней с пользовательскими параметрами выходных. Параметры выходного дня указывают, какое и сколько дней являются выходными днями. Выходные дни и все дни, указанные в качестве праздников, не считаются рабочими днями.
Синтаксис
expression. WorkDay_Intl (Arg1, Arg2, Arg3, Arg4)
Выражение Переменная, представляющая объект WorksheetFunction .
Параметры
Имя | Обязательный или необязательный | Тип данных | Описание | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Arg1 | Обязательный | Variant | Start_date — начальная дата, усеченная до целого числа. | ||||||||||||||||||||||||||||||
Arg2 | Обязательный | Variant | Days — количество рабочих дней до или после start_date. Положительное значение дает дату в будущем; отрицательное значение возвращает прошлую дату; значение 0 (ноль) возвращает start_date. Смещение дня усекается до целого числа. | ||||||||||||||||||||||||||||||
Arg3 | Необязательный | Variant | Выходные — указывает дни недели, которые являются выходными и не считаются рабочими днями. Weekend — это число или строка выходных, указывающая время выходных. Числовые значения выходных указывают на следующие выходные дни.
|
||||||||||||||||||||||||||||||
Arg4 | Необязательный | Variant | Праздники — необязательный набор из одной или нескольких дат, которые должны быть исключены из календаря рабочего дня. Праздники — это диапазон ячеек, содержащих даты или константу массива последовательного значения, представляющего эти даты. Порядок дат или серийных значений в праздники может быть произвольным. |
Возвращаемое значение
Double
Замечания
Если start_date выходит за пределы диапазона для текущего базового значения даты, WorkDay_Intl возвращает #NUM! значение ошибки.
Если какая-либо дата в праздники выходит за пределы диапазона для текущего базового значения даты, WorkDay_Intl возвращает #NUM! значение ошибки.
Если start_date плюс смещение дня возвращает недопустимую дату, WorkDay_Intl возвращает #NUM! значение ошибки.
Если строка выходных данных имеет недопустимую длину или содержит недопустимые символы, WorkDay_Intl возвращает #VALUE! значение ошибки.
Поддержка и обратная связь
Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.
Источник
Функция Weekday
Возвращает значение переменной Variant (Integer), отображающее дни недели.
Синтаксис
Weekday(date, [ firstdayofweek ])
Синтаксис функции Weekday состоит из таких именованных аргументов:
Part | Описание |
---|---|
дата | Обязательный аргумент. Переменная, числовое выражение, строковое выражение или любое выражение, отображающее дату. Если аргумент date содержит Null, возвращается значение Null. |
первый_день_недели | Необязательный аргумент. Константа, задающая первый день недели. Если она не указана, им является vbSunday. |
Settings
Аргумент первый_день_недели может принимать следующие значения:
Константа | Значение | Описание |
---|---|---|
vbUseSystem | 0 | Используются параметры API NLS. |
vbSunday | 1 | Воскресенье (по умолчанию) |
vbMonday | 2 | Понедельник |
vbTuesday | 3 | Вторник |
vbWednesday | 4 | Среда |
vbThursday | 5 | Четверг |
vbFriday | 6 | Пятница |
vbSaturday | 7 | Суббота |
Возвращаемые значения
Функция Weekday возвращает такие значения:
Константа | Значение | Описание |
---|---|---|
vbSunday | 1 | Воскресенье |
vbMonday | 2 | Понедельник |
vbTuesday | 3 | Вторник |
vbWednesday | 4 | Среда |
vbThursday | 5 | Четверг |
vbFriday | 6 | Пятница |
vbSaturday | 7 | Суббота |
Замечания
Если свойство Calendar имеет значение григорианский, возвращаемое целое число представляет григорианский день недели для аргумента date.
Если задан календарь хиджра, возвращаемое целое число означает день недели по календарю хиджра, соответствующий аргументу date. Для дат по календарю хиджра числовым аргументом является любое числовое выражение, представляющее дату или время с 1 января 100 года (2 августа 718 года по грегорианскому календарю) по 4 марта 9666 года (31 декабря 9999 года по грегорианскому календарю).
Пример
В этом примере функция Weekday возвращает день недели по указанной дате.
См. также
Поддержка и обратная связь
Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.
Источник
VBA Excel. Расчет рабочего времени
Расчет рабочего времени за период, ограниченный двумя датами, в течение одного года с помощью кода VBA Excel. Функция для расчета рабочего времени.
Календарь рабочего времени
Для расчета рабочего времени по двум датам нам понадобится производственный мини-календарь на год, состоящий из двух строк:
Создавать такой календарь вручную, не считая протяжку дат, довольно долго и нудно. Поэтому мы создадим производственный мини-календарь программно.
Для создания календаря рабочего времени из кода VBA Excel сначала следует запустить процедуру DaysOfYear, которая заполнит строку дат:
Для создания строки дат потребуется указать только два параметра: год и ячейку, с которой начинается эта строка.
Процедура DaysOfYear запускается из редактора VBA Excel и работает около минуты. Ускорить ее можно, используя массив, который заполняется датами и затем значения его элементов вставляются в диапазон дат.
В конце процедуры диапазону дат присваивается имя, по которому мы будем обращаться к нему в дальнейшем.
Заполнение строки часов
Допустим, нам нужен календарь с пятидневной 40-часовой рабочей неделей, в котором необходимо указать 8 часов для будничных дней и 0 часов — для выходных.
Заполняем строку рабочего времени из кода VBA Excel с помощью процедуры WorkingTimeDay, которая в ячейки строки времени под ячейками с субботой и воскресеньем вставляет 0, а под ячейками с буднями — 8:
Источник
Name already in use
VBA-Docs / api / Excel.WorksheetFunction.WorkDay.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
Copy raw contents
Copy raw contents
WorksheetFunction.WorkDay method (Excel)
Returns a number that represents a date that is the indicated number of working days before or after a date (the starting date). Working days exclude weekends and any dates identified as holidays. Use WorkDay to exclude weekends or holidays when you calculate invoice due dates, expected delivery times, or the number of days of work performed.
expression.WorkDay (Arg1, Arg2, Arg3)
expression A variable that represents a WorksheetFunction object.
Name | Required/Optional | Data type | Description |
---|---|---|---|
Arg1 | Required | Variant | Start_date — a date that represents the start date. |
Arg2 | Required | Variant | Days — the number of nonweekend and nonholiday days before or after start_date. A positive value for days yields a future date; a negative value yields a past date. |
Arg3 | Optional | Variant | Holidays — an optional list of one or more dates to exclude from the working calendar, such as state and federal holidays and floating holidays. The list can be either a range of cells that contain the dates or an array constant of the serial numbers that represent the dates. |
Double
[!IMPORTANT] Dates should be entered by using the DATE function, or as results of other formulas or functions. For example, use DATE(2008,5,23) for the 23rd day of May, 2008. Problems can occur if dates are entered as text .
Microsoft Excel stores dates as sequential serial numbers so they can be used in calculations. By default, January 1, 1900 is serial number 1, and January 1, 2008 is serial number 39448 because it is 39,448 days after January 1, 1900. Microsoft Excel for the Macintosh uses a different date system as its default.
[!NOTE] Visual Basic for Applications (VBA) calculates serial dates differently than Excel. In VBA, serial number 1 is December 31, 1899, rather than January 1, 1900.
If any argument is not a valid date, WorkDay returns the #VALUE! error value.
If start_date plus days yields an invalid date, WorkDay returns the #NUM! error value.
If days is not an integer, it is truncated.
Источник
В одном из заказов недавно столкнулся с проблемой получения праздничных дней согласно утвержденному производственному календарю. Да, я знаю, что в компаниях он может быть свой, отличный от опубликованного государством. И смысла как-то получать список праздничных дат с общедоступных порталов не было. Но вот именно сейчас потребовался именно общедоступный опубликованный календарь, чтобы можно было его автоматом скачать и применить. И оказалось, что это тоже не самая простая задача: многие календари в сети либо в формате 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) —Insert —Module. Вставляем туда код выше полностью. Или скачать файл ниже — там уже все сделано удобно и красиво:
Скачать файл с кодом:
В случае с 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»)). Это самая важная строка в текущей задаче — она получает исходный текст страницы сайта в виде разбитого на строки текста, в котором потом можно будет просматривать и искать нужное нам
а дальше по сути идет тоже самое, что делалось кодом 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 и просмотреть по шагам все действия:
Но если вдруг это надо будет — пишите в комментариях, постараюсь описать процесс наглядно(в будущем подготовлю видеоурок на данную тему).
0 / 0 / 0 Регистрация: 05.12.2016 Сообщений: 86 |
|
1 |
|
Заполнение выходных дней19.08.2019, 15:20. Показов 1859. Ответов 7
Добрый день, коллеги) Передо мной встала такая задача: Спасибо большое заранее.
0 |
0 / 0 / 0 Регистрация: 05.12.2016 Сообщений: 86 |
|
19.08.2019, 15:31 [ТС] |
2 |
Добавляю пример отчетности.
0 |
1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
|
20.08.2019, 17:43 |
3 |
Hikitosik, а что за сложности?
1 |
0 / 0 / 0 Регистрация: 05.12.2016 Сообщений: 86 |
|
21.08.2019, 12:13 [ТС] |
4 |
Это всё классно, уже попробовал реализовать. Всё можно сделать циклом, поскольку компаний константное количество. Даже формулу можно вывести Но хотелось бы, чтобы это делалось каким-то алгоритмом, который будет искать дни, которые были пропущены, и далее вставлять данные с ближайшей слева заполненной даты. Просто интересно не само заполнение выходных, а любого пропущенного дня. Тут я уже в ступоре, как проверить на отсутствие и скопировать необходимые данные. Пока ни одной толковый мысли не пришло, кроме как копировать и вставлять вручную))))
0 |
1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
|
21.08.2019, 16:20 |
5 |
копировать и вставлять вручную Что ж тоже вариант, только перед этим включить запись макроса, а после выполнения всех действий по копированию делаем Остановить запись. Получили макрос. Только вместо номера конкретного столбца ставите переменную, в которую вставляете индекс пустого столбца. А поиск пустой ячейки первой строки ну совсем просто — последовательной проверкой на космическую пустоту. В макрос вставляете добавление даты этого нового столбца на ещё 1 день.
0 |
0 / 0 / 0 Регистрация: 05.12.2016 Сообщений: 86 |
|
21.08.2019, 20:34 [ТС] |
6 |
Наверно, мы друг друга не совсем понимаем) Плюс проблема возникает в том, что таблица растёт в ширь. То есть необходимо будет приписывать справа к ней недостающие даты. Пока не осознал, как это правильно сделать
0 |
КостяФедореев Часто онлайн 792 / 530 / 238 Регистрация: 09.01.2017 Сообщений: 1,820 |
||||
22.08.2019, 00:07 |
7 |
|||
Hikitosik, попробуйте
Добавлено через 2 минуты Добавлено через 8 минут
2 |
1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
|
22.08.2019, 05:10 |
8 |
Hikitosik, у вас там в примере идет пустой столбец, я ориентировался по нему. Если пропущена дата, то это тоже просто, проверяешь разницу дат и, если больше 1, то делаешь то, что я писал. Мне хотелось, чтобы вы попробовали сами справиться и помочь в случае чего. Но если КостяФедореев взялся, то он вам всё напишет без проблем и без обучения. Удачи.
2 |
Расчет рабочего времени за период, ограниченный двумя датами, в течение одного года с помощью кода VBA Excel. Функция для расчета рабочего времени.
Календарь рабочего времени
Для расчета рабочего времени по двум датам нам понадобится производственный мини-календарь на год, состоящий из двух строк:
Создавать такой календарь вручную, не считая протяжку дат, довольно долго и нудно. Поэтому мы создадим производственный мини-календарь программно.
Для создания календаря рабочего времени из кода VBA Excel сначала следует запустить процедуру DaysOfYear, которая заполнит строку дат:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Sub DaysOfYear() Dim y As String, c1 As Range, i As Integer ‘Указываем год, для которого нужна строка дат y = «2023» ‘Указываем ячейку, в которой будет первый день года Set c1 = Cells(1, 2) ‘В первую ячейку строки с датами вставляем первый день года c1 = CDate(«01.01.» & y) ‘Задаем формат отображения даты c1.NumberFormat = «dd.mm.yy» ‘Заполняем выбранную строку со 2 дня до конца года Do While c1.Offset(0, i) <> CDate(«31.12.» & y) c1.Offset(0, i + 1) = c1.Offset(0, i) + 1 c1.Offset(0, i + 1).NumberFormat = «dd.mm.yy» i = i + 1 Loop ‘Присваиваем диапазону дат имя Range(c1, c1.End(xlToRight)).Name = «Год» & y End Sub |
Для создания строки дат потребуется указать только два параметра: год и ячейку, с которой начинается эта строка.
Процедура DaysOfYear запускается из редактора VBA Excel и работает около минуты. Ускорить ее можно, используя массив, который заполняется датами и затем значения его элементов вставляются в диапазон дат.
В конце процедуры диапазону дат присваивается имя, по которому мы будем обращаться к нему в дальнейшем.
Заполнение строки часов
Допустим, нам нужен календарь с пятидневной 40-часовой рабочей неделей, в котором необходимо указать 8 часов для будничных дней и 0 часов — для выходных.
Заполняем строку рабочего времени из кода VBA Excel с помощью процедуры WorkingTimeDay, которая в ячейки строки времени под ячейками с субботой и воскресеньем вставляет 0, а под ячейками с буднями — 8:
Public Sub WorkingTimeDay() Dim c As Range For Each c In Range(«Год2023») If Weekday(c, vbMonday) = 6 Or Weekday(c, vbMonday) = 7 Then c.Offset(1, 0) = 0 Else c.Offset(1, 0) = 8 End If Next End Sub |
Ну и для полной достоверности, следует исключить из группы рабочих праздничные дни, для чего запускаем из редактора VBA Excel следующую процедуру:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Sub Holidays2023() ‘Нерабочие праздничные дни в 2023 году: ‘с 1 по 8 января — 8 дней; ‘с 23 по 26 февраля — 4 дня; ‘8 марта; ‘с 29 апреля по 1 мая — 3 дня; ‘с 6 по 9 мая — 4 дня; ‘с 10 по 12 июня — 3 дня; ‘с 4 по 6 ноября — 3 дня. Dim c As Range For Each c In Range(«Год2023») Select Case c Case CDate(«01.01.2023») To CDate(«08.01.2023») c.Offset(1, 0) = 0 Case CDate(«23.02.2023») To CDate(«26.02.2023») c.Offset(1, 0) = 0 Case CDate(«08.03.2023») c.Offset(1, 0) = 0 Case CDate(«29.04.2023») To CDate(«01.05.2023») c.Offset(1, 0) = 0 Case CDate(«06.05.2023») To CDate(«09.05.2023») c.Offset(1, 0) = 0 Case CDate(«10.06.2023») To CDate(«12.06.2023») c.Offset(1, 0) = 0 Case CDate(«04.11.2023») To CDate(«06.11.2023») c.Offset(1, 0) = 0 End Select Next End Sub |
Процедура Holidays2023 ищет в диапазоне дат праздничные дни и в соответствующие им ячейки строки рабочего времени вставляет нули.
Расчет рабочего времени
Расчет рабочего времени за период, ограниченный двумя датами, будем производить с помощью функции WorkingPeriodHours:
Public Function WorkingPeriodHours(date1, date2) If date2 < date1 Or Not IsDate(date1) Or Not IsDate(date2) Then WorkingPeriodHours = «Укажите период» Exit Function End If Dim i As Integer, d1 As Integer, d2 As Integer, h As Integer d1 = date1 — Range(«Год2023»).Cells(1) + 1 d2 = date2 — Range(«Год2023»).Cells(1) + 1 For i = d1 To d2 h = h + Range(«Год2023»).Cells(i).Offset(1, 0) Next WorkingPeriodHours = h End Function |
Если в ячейках, являющихся аргументами функции WorkingPeriodHours, будут указаны не даты или даты в неправильном порядке (первая дата больше второй), функция возвратит сообщение: «Укажите период». Если будут указаны неверные даты, не входящие в диапазон дат, функция возвратит значение ошибки: «#ЗНАЧ!».
Код функции размещается в стандартном модуле.
Для вставки в ячейку функция WorkingPeriodHours будет доступна в категории «Определенные пользователем» мастера функций Excel.