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]
Определяем день ( рабочий или выходной) |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
aequit Пользователь Сообщений: 209 |
#1 17.01.2020 10:45:20 Здравствуйте!
, может кому пригодится. Можно разместить в личной книге макросов или надстройке. В конце года после выхода постановления Правительства РФ необходимо добавлять в код данные по праздничным и выходным дням, а также по рабочим субботам (внесены данные с 01.01.2015 по текущий год).
Прикрепленные файлы
Изменено: aequit — 17.01.2020 11:13:53 |
|
Jack Famous Пользователь Сообщений: 10848 OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome |
aequit, здравствуйте! Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄ |
Тоже такое делал, но что по мне, то более userfriendly делать именно с возможностью указания диапазонов праздников и рабочих суббот(я делал через именованные диапазоны), т.к. в разных компаниях эти даты могут отличаться. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
|
egonomist Пользователь Сообщений: 409 |
День добрый. Сейчас появился еще один вариант , используя веб-запрос, даже R пакет сделали с его использованием. |
aequit Пользователь Сообщений: 209 |
#5 17.01.2020 14:03:27
Спасибо, работает (только предварительно нужно создать в книге лист с именем «temp», иначе макрос вываливается в ошибку. |
||
Jack Famous Пользователь Сообщений: 10848 OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome |
#6 17.01.2020 14:48:48 aequit, Вместо цикла по массиву праздников, загоняем список в словарь. Метод Exists позволит проверить наличие даты в словаре сильно быстрее. Можно пойти далее и держать словарь в памяти, чтобы не создавать его для каждого вызова функции — будет совсем круто
можно сделать этот аргумент-диапазон опциональным и, если он не указан, то использовать встроенный справочник, а если указан, то заменить/дополнить список. Типа компромисс. Но за каждый такой компромисс придётся расплачиваться скоростью… Изменено: Jack Famous — 17.01.2020 14:49:43 Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄ |
||
aequit Пользователь Сообщений: 209 |
#7 18.01.2020 20:43:03
Сделал.
Сделал.
Измерил скорость работы путём заполнения формулой с функцией 500000 ячеек в столбце (при этом происходил её расчёт в каждой ячейке) . Прикрепленные файлы
|
|||||||
Jack Famous Пользователь Сообщений: 10848 OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome |
aequit, рад, что помогло Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄ |
lizardjazz1 Пользователь Сообщений: 1 |
Доброго времени суток, а можно ли как-то подсчитать рабочее время, например рабочий день с 8 до 18, я изначально делал это формулой, вроде считает, но потом когда к четвергу прибавляется два, три дня, он не переносит на понедельник, а ещё может поставить время позже 18 или раньше 8 Так вот, как можно бы добавить в эту функцию ещё и счёт времени, натолкните на мысль? Прикрепленные файлы
|
aequit Пользователь Сообщений: 209 |
#10 25.01.2020 09:01:30
Непонятно, что Вы хотите получить? Попробуйте человеку, незнакомому с Вашей задачей (например, коллеге за соседним столом) дать прочитать её и потом спросите: «Понятно и доходчиво я описал требуемое?» |
||
БМВ Модератор Сообщений: 21378 Excel 2013, 2016 |
#11 25.01.2020 09:41:18
непонятно не это, a то как вопрос связан с начальной темой По вопросам из тем форума, личку не читаю. |
||
ближайший рабочий день он и без VBA ближайший рабочий день, только очень сильно зависит от праздников страны в которой вы живете. Изменено: Ігор Гончаренко — 25.01.2020 09:41:49 Программисты — это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете! |
|
aequit Пользователь Сообщений: 209 |
#13 25.01.2020 09:45:41
Еще и от региона страны. Ближайший пример: у нас в области 28 декабря 2019 года был объявлен рабочим днём, а 31 декабря 2019 года — выходным. |
||
да, я именно об этом Программисты — это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете! |
|
DimasAda Пользователь Сообщений: 2 |
#15 11.02.2021 12:24:41
Добрый день. Дублирую сюда еще. https://www.cyberforum.ru/blogs/307973/blog6287.html Доработал для чтения массива выходных из диапазона ячеек, но не смог победить одну проблему: Прошу помочь с поиском решения |
||
aequit Пользователь Сообщений: 209 |
#16 11.02.2021 16:13:23
Так создайте свою тему, опишите, что хотите получить и приложите пример. VBA |
||
Почему-то ругается на «new dictionary» в модуле в моем файле, выдает ошибку invalid use of new keyword site:stackoverflow.com |
|
aequit Пользователь Сообщений: 209 |
Сергей bangoo, |
Подключен, разобрался, была подключена библотека вордовская которая была выше в иерархии и перехватывала dictionary. |
|
aequit Пользователь Сообщений: 209 |
#20 19.09.2022 08:24:52
Да, это и требуется. |
||
Содержание
- Обзор функции РАБДЕНЬ
- РАБДЕНЬ Синтаксис и входные данные функции:
- Найти ближайший рабочий день
- РАБДЕНЬ в Google Таблицах
- WORKDAY Примеры в VBA
Скачать пример рабочей книги
Загрузите образец книги
В этом руководстве показано, как использовать Функция РАБДЕНЬ в Excel в Excel добавить рабочие дни.
Обзор функции РАБДЕНЬ
Функция РАБДЕНЬ Возвращает рабочий день n количество рабочих дней (рабочие дни, исключая выходные: суббота и воскресенье) с даты начала. По желанию можно исключить праздники. Для нестандартных выходных используйте WORKDAY.INTL.
Чтобы использовать функцию рабочего листа Excel WORKDAY, выберите ячейку и введите:
(Обратите внимание, как появляется ввод формулы)
РАБДЕНЬ Синтаксис и входные данные функции:
1 | = РАБДЕНЬ (начальная_дата, дни, праздники) |
Дата начала — Дата начала в формате серийного номера Excel или введенная как дата с цитатами вокруг даты. Пример: нельзя вводить 11.12.2015 прямо в ячейку. Вместо этого вам нужно ввести «11/12/2015», или вам нужно будет использовать соответствующий серийный номер: 42320. В качестве альтернативы вы можете указать ячейку с введенной датой 11/12/2015. Excel автоматически преобразует даты, хранящиеся в ячейках, в последовательный формат (если дата не вводится как текст).
дней — Количество не выходных и не выходных дней с даты начала.
каникулы — ПО ЖЕЛАНИЮ. Массив со списком дат, представляющих праздники, которые следует исключить из рабочих дней.
Найти ближайший рабочий день
Чтобы найти ближайший рабочий день, используйте функцию РАБДЕНЬ:
Найти ближайший к сегодняшнему дню рабочий день
Чтобы найти ближайший к сегодняшнему дню рабочий день, используйте функцию СЕГОДНЯ с функцией РАБДЕНЬ:
1 | = РАБДЕНЬ (СЕГОДНЯ (); B3) |
Найти ближайший рабочий день за 10 дней
В этом примере будет найден ближайший рабочий день через 10 дней от даты начала:
Вы также можете использовать отрицательные дни для поиска рабочих дней в прошлом:
Рабочий день с праздниками
По умолчанию РАБДНИ игнорируют все праздники. Однако вы можете использовать третий необязательный аргумент для определения диапазона праздников:
1 | = РАБДЕНЬ (B3; C3; F3: F4) |
РАБДЕНЬ в Google Таблицах
Функция РАБДЕНЬ в Google Таблицах работает точно так же, как и в Excel:
WORKDAY Примеры в VBA
Вы также можете использовать функцию РАБДЕНЬ в VBA. Тип:Application.Worksheetfunction.Workday (начальная_дата, дни, праздники)
Выполнение следующих операторов VBA
123 | Диапазон («E2») = Application.WorksheetFunction.WorkDay (Диапазон («B2»), Диапазон («C2»))Диапазон («E3») = Application.WorksheetFunction.WorkDay (Диапазон («B3»), Диапазон («C3»))Диапазон («E4») = Application.WorksheetFunction.WorkDay (Диапазон («B4»), Диапазон («C4»), Диапазон («D4»)) |
даст следующие результаты
Для аргументов функции (начальная_дата и т. Д.) Вы можете либо ввести их непосредственно в функцию, либо определить переменные для использования вместо них.
Вернуться к списку всех функций в Excel
Вы поможете развитию сайта, поделившись страницей с друзьями
Расчет рабочего времени за период, ограниченный двумя датами, в течение одного года с помощью кода 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.
Хитрости »
23 Октябрь 2017 10915 просмотров
Проблема получения последнего дня месяца довольно распространена и очень просто решается. Начиная с Excel 2007 можно без всяких доп.манипуляций использовать функцию КОНМЕСЯЦА(EOMONTH):
=КОНМЕСЯЦА(ТДАТА();0)
=EOMONTH(NOW(),0)
ТДАТА(NOW) — возвращает текущую дату. Вместо неё можно указать любую дату и последняя дата месяца будет возвращена для указанной даты.
Для версий 2003 и ранее для использования КОНМЕСЯЦА(EOMONTH) необходимо для начала подключить надстройку Пакет анализа или же использовать чуть менее понятную формулу:
=ДАТА(ГОД(ТДАТА());МЕСЯЦ(ТДАТА())+1;0)
=DATE(YEAR(NOW()),MONTH(NOW())+1,0)
На самом деле данная формула проста, если разобраться детальнее. Функция ДАТА записывает в ячейку дату, на основании указанного года, месяца и дня. Мы для года берем год от текущей даты, далее берем месяц текущей даты и к месяцу прибавляем 1, чтобы получить следующий месяц. А потом для дня указываем 0, что заставляет Excel сдвинуть первую дату следующего месяца на один день назад. Таким образом и получается последняя дата месяца. Пошагово это выглядит так(если считать, что сегодня «22.10.2017»):
=ДАТА(ГОД(ТДАТА());МЕСЯЦ(ТДАТА())+1;0) =>
=ДАТА(ГОД(«22.10.2017»);МЕСЯЦ(«22.10.2017»)+1;0) =>
=ДАТА(2017;10+1;0) =>
=ДАТА(2017;11;0) здесь уже получится 01.11.2017, но 0 в качестве дня заставляет вернуться на день назад =>
=31.10.2017
Но есть более сложная проблема — получить дату последнего рабочего дня месяца. А это уже не так просто. Встроенных функций(вроде КОНМЕСЯЦА) для этого в Excel нет. А это значит опять придется танцевать с бубном.
Сразу возникает вопрос: а зачем это вообще может потребоваться? Например, для поиска счетов, отгрузка по которым производилась в последний рабочий день месяца, а оплаты(или документы на отгрузку) по некоторым пришли только в начале следующего. Так же такую функцию будет удобно применять для автоматического формирования платежек или накладных, если они должны быть оформлены именно последним рабочим днем месяца.
Чтобы получить именно корректную дату следует так же учесть и тот факт, что есть дни праздничные. И их тоже надо как-то учесть. Для этого я буду использовать отдельный лист Праздники, в столбце А которого записаны праздничные дни на пару лет. Также в этом диапазоне перечислены и все выходные. Сделано для более корректного подсчета дат, т.к. праздники могут быть перенесены, в результате чего рабочими становятся субботы или воскресенья. Если их не учитывать, то расчет будет неверным.
Из спортивного интереса создать такую функцию решил тремя способами:
- При помощи стандартных функций Excel
- При помощи функции пользователя на VBA
- При помощи PowerQuery
Последний рабочий день при помощи стандартных функций Excel
В ходе некоторых экспериментов и манипуляций появилась такая формула:
=РАБДЕНЬ(
ЕСЛИ(ДЕНЬНЕД(КОНМЕСЯЦА(B4;0);2)<6; КОНМЕСЯЦА(B4;0);
КОНМЕСЯЦА(B4;0)-(ДЕНЬНЕД(КОНМЕСЯЦА(B4;0);2)-5));
0; Праздники!$A$2:$A$827)
=WORKDAY(
IF(WEEKDAY(EOMONTH(B4,0),2)<6, EOMONTH(B4,0),
EOMONTH(B4,0)-(WEEKDAY(EOMONTH(B4,0),2)-5)),
0,Праздники!$A$2:$A$827)
где Праздники!$A$2:$A$827 — ссылка на диапазон дат с праздниками
Здесь я так же использую КОНМЕСЯЦА для быстрого определения последней даты месяца.
Функция ДЕНЬНЕД(WEEKDAY) возвращает номер дня недели для указанной даты и нужна для того, чтобы определить — является последний день недели субботой или воскресеньем. Если нет, то возвращаем дату как есть, если это суббота или воскресенье — то отнимаем от даты либо 1 день, либо 2(если это СБ — то 1, если ВСК — то 2).
И только после этого применяем к полученной дате функцию РАБДЕНЬ(WORKDAY), которая для последней даты месяца определяет, является ли она праздничной(на основании списка праздников Праздники!$A$2:$A$827). Если дата праздничная — то она уменьшается до тех пор, пока не достигнет рабочего дня. РАБДЕНЬ не принимает в расчет выходные, поэтому нам и нужны функции ЕСЛИ и ДЕНЬНЕД, прежде чем применить РАБДЕНЬ.
Однако сразу хочу оговорить, что в конкретно моем случае вычисление выходных дней при помощи ЕСЛИ и ДЕНЬНЕД несколько избыточно, т.к. в диапазоне с праздниками помимо непосредственно праздников у меня уже учтены все выходные дни. Т.е. по сути формула могла бы быть намного проще:
=РАБДЕНЬ(КОНМЕСЯЦА(B4;0); 0; Праздники!$A$2:$A$827)
=WORKDAY(EOMONTH(B4,0), 0, Праздники!$A$2:$A$827)
Но я все равно решил именно в статье привести формулу, которая смотрит и на дни недели, т.к. требования могут быть разными.
Т.к. Microsoft все же немного заботится о нас, то для пользователей версий Excel 2010 и более новых, в случае необходимости учитывать день недели прямо в формуле, можно использовать функцию РАБДЕНЬ.МЕЖД:
=РАБДЕНЬ.МЕЖД(КОНМЕСЯЦА(B4;0);0;1;Праздники!$A$2:$A$827)
=WORKDAY.INTL(EOMONTH(B4,0),0,1,Праздники!$A$2:$A$827)
РАБДЕНЬ.МЕЖД[дата; кол-во дней; выходные; праздники]
дата — дата, от которой необходимо отсчитать указанное кол-во дней
кол-во дней — количество дней, которые надо прибавить или отнять(отриц. число — отнимает дни от даты) от указанной даты
выходные — 1 = Суббота и Воскресенье, 2 — Воскресенье и Понедельник и т.д. Полный перечень есть в справке для функции и в выпадающей подсказке к функции при вводе.
праздники — ссылка на диапазон дат с праздниками
Достаточно указать последнюю дату месяца, указать для неё сдвиг на 0 дней, указать тип выходных и ссылку на диапазон дат с праздниками. Все уже сделано и все гораздо проще.
Последний рабочий день при помощи функции пользователя на VBA
Если использование VBA не является для вас проблемой, то можно применить функцию пользователя(UDF) для расчета последнего рабочего дня:
'--------------------------------------------------------------------------------------- ' Author : The_Prist(Щербаков Дмитрий) ' Профессиональная разработка приложений для MS Office любой сложности ' Проведение тренингов по MS Excel ' http://www.excel-vba.ru ' WebMoney - R298726502453; Яндекс.Деньги - 41001332272872 ' Purpose: Функция получения последнего рабочего дня на основании указанной даты и списка праздников '--------------------------------------------------------------------------------------- Option Explicit Function ПоследнийРабочийДень(Дата As Date, Optional Праздники As Range = Nothing, Optional СистемныеВыходные As Boolean = False) Dim dd As Date, dres As Date Dim lWeekDay As Long dres = DateSerial(Year(Дата), Month(Дата) + 1, 0) If СистемныеВыходные Then lWeekDay = Weekday(dres, vbUseSystemDayOfWeek) If lWeekDay < 6 Then dres = dres Else dres = dres - (lWeekDay - 5) End If End If Do While (IsHoliday(dres, Праздники)) dres = dres - 1 Loop ПоследнийРабочийДень = dres End Function 'Функция поиска указанной даты среди праздничных дат ' dd - искомая дата ' Holidays - диапазон с праздничными днями Function IsHoliday(ByVal dd As Date, Optional Holidays As Range = Nothing) Dim lWeekDay As Long Dim x, rr As Range If Holidays Is Nothing Then Exit Function For Each x In Holidays.Value If IsDate(x) Then If CDate(x) = dd Then IsHoliday = True Exit Function End If End If Next End Function
Чтобы правильно использовать приведенный код, необходимо сначала ознакомиться со статьей Что такое функция пользователя(UDF)?. Вкратце: скопировать текст кода выше, перейти в редактор VBA(Alt+F11) -создать стандартный модуль(Insert —Module) и в него вставить скопированный текст. После чего функцию можно будет вызвать из Диспетчера функций(Ctrl+F3), отыскав её в категории Определенные пользователем (User Defined Functions).
Синтаксис функции:
=ПоследнийРабочийДень(B4;Праздники!$A$2:$A$827;0)
- Дата(B4) — непосредственно дата или ссылка на ячейку с датой, последней рабочий день для которой необходимо вычислить. Будет рассчитан последний рабочий день для месяца указанной даты.
- Праздники() — ссылка на диапазон ячеек, содержащих даты праздничных дней.
- СистемныеВыходные(0) — ИСТИНА(TRUE или 1) или ЛОЖЬ(FALSE или 0). Если указано как ЛОЖЬ, то при вычислении последнего рабочего дня не будут учитываться выходные. В этом случае они обязательно должны быть перечислены в списке Праздники. Если они не перечислены — то все дни недели считаются рабочими, кроме праздников. Если указано как ИСТИНА, то в качестве выходных будут применены те дни, которые установлены для календаря в операционной системе. Для русской локализации это как правило Суббота и Воскресенье.
Последний рабочий день при помощи PowerQuery
Самый экзотический метод. Если еще не знаете что такое PowerQuery — Power Query — что такое и почему её необходимо использовать в работе?.
Для начала необходимо загрузить список праздников.
Если список праздников еще не преобразован в умную таблицу, то на листе Праздники выделяем все ячейки с датами -переходим на вкладку Вставка(Insert) –Таблица(Table). Снимаем галку с пункта «Таблица с заголовками» —Ок:
Выделяем любую ячейку в созданной таблице праздников -переходим на вкладку Данные(Data или Power Query) и выбираем Из таблицы(From Table).
Нажимаем в заголовке на значок календаря и в выпадающем списке выбираем тип Дата:
В правой части окна редактора изменяем название запроса(скорее всего там Таблица1) на Праздники:
Переходим на вкладку Главная, раскрываем пункт Закрыть и загрузить и выбираем Закрыть и загрузить в…:
В появившемся окне выбираем Только создать подключение и нажимаем Ок:
Теперь переходим на вкладку Данные(Data) -Получить данные -Из других источников -Пустой запрос. Переходим в расширенный редактор(вкладка Главная —Расширенный редактор):
и вставляем туда следующий текст:
let
dNow = Date.From(DateTime.LocalNow()),
//dNow = Date.FromText(«2017-09-19»),
lastDay = Date.EndOfMonth(dNow),
WeekD = Date.DayOfWeek(lastDay,1),
dd = if WeekD < 5 then lastDay else Date.AddDays(lastDay,-(WeekD-4)),
//dd = dNow,
coun_dif = (value as date) as date =>
let
dAdd = value,
select_rows = Table.SelectRows(Праздники, each Record.Field(_, «Дата выходного дня») = dAdd),
count_rows = Table.RowCount(select_rows),
result = Date.AddDays(value,-count_rows)
in
result,
res_d = Table.FromValue(coun_dif(dd))
in
res_d
После этого можно на вкладке Главная нажать Закрыть и загрузить. Будет создан новый лист с одной ячейкой — датой последнего рабочего дня.
Чтобы приведенный запрос работал корректно, необходимо назвать столбец с праздничными датами «Дата выходного дня». Либо изменить это название в самом запросе.
Если нужен последний рабочий день на конкретную дату, то необходимо убрать первую строку(dNow = Date.From(DateTime.LocalNow()),) и убрать слеши вначале следующей строки:
let
dNow = Date.FromText(«2017-09-19»),
lastDay = Date.EndOfMonth(dNow),
WeekD = Date.DayOfWeek(lastDay,1),
dd = if WeekD < 5 then lastDay else Date.AddDays(lastDay,-(WeekD-4)),
//dd = Date.EndOfMonth(dNow),
coun_dif = (value as date) as date =>
let
dAdd = value,
select_rows = Table.SelectRows(Праздники, each Record.Field(_, «Дата выходного дня») = dAdd),
count_rows = Table.RowCount(select_rows),
result = Date.AddDays(value,-count_rows)
in
result,
res_d = Table.FromValue(coun_dif(dd))
in
res_d
Если выходные не надо учитывать(чтобы суббота и воскресенье не рассчитывались автоматом в зависимости от дня недели), то запрос будет выглядеть так:
let
dNow = Date.FromText(«2017-09-19»),
dd = Date.EndOfMonth(dNow),
coun_dif = (value as date) as date =>
let
dAdd = value,
select_rows = Table.SelectRows(Праздники, each Record.Field(_, «Дата выходного дня») = dAdd),
count_rows = Table.RowCount(select_rows),
result = Date.AddDays(value,-count_rows)
in
result,
res_d = Table.FromValue(coun_dif(dd))
in
res_d
Реализацию всех приведенных решений можно скачать в приложенном файле
Скачать файл:
ПоследнийРабочийДень.xlsm (50,7 KiB, 617 скачиваний)
Статья помогла? Поделись ссылкой с друзьями!
Видеоуроки
Поиск по меткам
Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика
0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
|
1 |
|
Excel Нужно определить количество определенных рабочих дней недели и или их комбинаций в интервале дат15.08.2018, 11:14. Показов 6996. Ответов 43
Здравствуйте! Не смог найти подходящую тему. Задача состоит в том, что-бы посчитать количество рабочих дней недели и их комбинации (понедельник; понедельник, среда, пятница; и т.д.) в интервале дат. При этом нужно учитывать праздничные дни. Нашел только как их по отдельности искать.
0 |
Loya 70 / 57 / 24 Регистрация: 06.12.2015 Сообщений: 300 |
||||
15.08.2018, 15:04 |
2 |
|||
А где в файле код? Посчитать рабочие дни можно так (предполагаем, что как в приложенном файле начало периода указано в ячейкеА1, конец периода в ячейке А2, перечисление праздничных дней начинается с ячейки А7):
Про комбинации рабочих дней не совсем понятно, по одному дню это тоже комбинация? Должно быть:
0 |
0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
|
15.08.2018, 16:20 [ТС] |
3 |
Loya, спасибо огромное, за ответ! Сейчас попробую понятнее объяснить что именно нужно:
0 |
70 / 57 / 24 Регистрация: 06.12.2015 Сообщений: 300 |
|
15.08.2018, 17:16 |
4 |
Т.е. вывод по заданным датам (15.08.2018 — 23.08.2018) должен быть: А, например, за период 3.05.2018-14.05.2018 вывод должен быть такой: Так что-ли?
0 |
Burk 1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
||||
16.08.2018, 08:42 |
5 |
|||
PiLLyulk, такой вариант
Добавлено через 8 минут
0 |
0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
|
16.08.2018, 10:20 [ТС] |
6 |
Loya, добрый день.
Т.е. вывод по заданным датам (15.08.2018 — 23.08.2018) должен быть: Да, я думаю, что как-то так это должно быть. Тут самое главное что-бы можно было выбрать конкретные дни недели. Добавлено через 29 минут Вот эта часть вообще не понял что делать должна:
Do While Cells(I, 1) <> «»
0 |
1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
|
16.08.2018, 12:04 |
7 |
Вот эта часть вообще не понял что делать должна Да, тяжелый случай, эта часть вычитает из рабочих дней праздники заданного промежутка. Добавлено через 7 минут
0 |
0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
|
16.08.2018, 12:15 [ТС] |
8 |
Да, тяжелый случай, эта часть вычитает из рабочих дней праздники заданного промежутка. Вроде понял теперь, она перебирает даты, начиная с 10 строки, и если они попадают в заданный интервал, то вычитает их количество.
For I = 1 To 7 Спасибо, что возитесь со мной.
0 |
Loya 70 / 57 / 24 Регистрация: 06.12.2015 Сообщений: 300 |
||||
16.08.2018, 13:21 |
9 |
|||
Там их всего 15, из них 4 выходных и 1 праздничный день. Не понимаю что она имеет ввиду. Праздничных два (1.05.2019 и 9.05.2019).
Да, я думаю, что как-то так это должно быть. Тут самое главное что-бы можно было выбрать конкретные дни недели.
Всего 1 вторник и 2 четверга, 1 из этих дней праздничный, значит всего 2 штуки. Вот тут непонятно, нужно праздничный учитывать как вторник или нет? Если нужно то вот так примерно:
Если праздничный не нужно учитывать, как день недели, то подправьте условие.
Да, тяжелый случай Уважаю Вас и Ваше желание помочь, но зачем же так грубо? Все когда-то начинали. Разбирать чужой код даже опытному порой бывает сложно, а начинающему это сложно втройне. Добавлено через 3 минуты
Спасибо, что возитесь со мной. Можно жмакать кнопку «Спасибо» по сообщением, тогда у тех, кто «возится» будет расти репутация!
0 |
0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
|
16.08.2018, 14:19 [ТС] |
10 |
Loya, спасибо! Это, практически то, что нужно.
Праздничных два (1.05.2019 и 9.05.2019). Точно, я пор 1 мая забыл!
Вот тут непонятно, нужно праздничный учитывать как вторник или нет? Если нужно то вот так примерно: Дни недели, попадающие на праздники не нужно учитывать. По итогу, если взять тот же пример: с 1 мая 2019 по 15 мая 2019 и выбрать вторник и четверг, то ответ должен получиться 3. (2 вторникa и 1 четверг, который не праздничный). Получается, что нужно еще раз перебрать праздничные дни?
0 |
1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
|
16.08.2018, 14:27 |
11 |
PiLLyulk, про случай я сказал по поводу того, что вы не знаете, что делать с присланным кодом.
0 |
1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
|
16.08.2018, 14:33 |
12 |
PiLLyulk, в примере я поставил только один праздник 1 мая, если у вас в списке в А11 стоит и 9 иая, то должно быть 9
0 |
70 / 57 / 24 Регистрация: 06.12.2015 Сообщений: 300 |
|
16.08.2018, 15:10 |
13 |
Получается, что нужно еще раз перебрать праздничные дни? Нет, зачем два раза? Лучше переписать придерживаясь необходимых условий. Просто непонятно, субботы и воскресенья нужно считать или нет? Мы их не считаем в количестве рабочих дней, а общее количество суббот и воскресений нужно? Если нужно, то опять вопрос, считаем ли субботу, если она выпадает на праздник (например, 5 января)? Т.е. нужно определиться с условием, для того, чтоб понять в какой момент перебирать праздничные дни, а в какой проверять день на «выходнойвость».
0 |
1813 / 1135 / 346 Регистрация: 11.07.2014 Сообщений: 4,002 |
|
16.08.2018, 15:11 |
14 |
PiLLyulk, Cells(I, 1) = (D2 — I) 7 — (D1 — I — 1) 7 считает сколько I-ых дней недели в интервале дат
0 |
0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
|
16.08.2018, 15:48 [ТС] |
15 |
Нет, зачем два раза? Лучше переписать придерживаясь необходимых условий. Просто непонятно, субботы и воскресенья нужно считать или нет? Мы их не считаем в количестве рабочих дней, а общее количество суббот и воскресений нужно? Если нужно, то опять вопрос, считаем ли субботу, если она выпадает на праздник (например, 5 января)? Т.е. нужно определиться с условием, для того, чтоб понять в какой момент перебирать праздничные дни, а в какой проверять день на «выходнойвость». Выходные тоже нужно считать, если они выбраны. Тут смысл именно в том, что-бы посчитать сумму выбранных дней недели в определенном промежутке времени и что-бы туда праздники не попали. Выходные могут и понадобиться.
0 |
Loya 70 / 57 / 24 Регистрация: 06.12.2015 Сообщений: 300 |
||||
16.08.2018, 16:57 |
16 |
|||
Сообщение было отмечено PiLLyulk как решение РешениеВ таком случае сначала проверяем праздники, и если не праздничный, то записываем в массив, затем проверяем на выходнойство, если будни то увеличиваем ещё и счётчик рабочих дней. 5 января в этом случае в количество суббот не попадёт, что соответствует условию:
Тут смысл именно в том, что-бы посчитать сумму выбранных дней недели в определенном промежутке времени и что-бы туда праздники не попали. Вот примерно так:
1 |
0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
|
17.08.2018, 01:00 [ТС] |
17 |
Вот примерно так: Спасибо! Это то, что нужно! Добавлено через 53 минуты Я понял, что для полного счастья, этот макрос хочу превратить в функцию, брать дни недели из ячейки и в качестве ответа получать сумму этих выбранных дней. Похоже, что это реально сделать. Помогите, пожалуйста, как сделать так что-бы он брал из ячейки нужные дни недели. И еще не могу понять как вывести нужный ответ в ячейку.
0 |
Loya 70 / 57 / 24 Регистрация: 06.12.2015 Сообщений: 300 |
||||
17.08.2018, 13:02 |
18 |
|||
PiLLyulk, ну смотрите, вот тут:
bDate = CDate(Cells(1, 1)) Объявлены две переменные, которые как раз инициализируются данными из ячеек, преобразованными к типу Date. Т.е. если Вам нужно брать дни тоже из ячеек, то по аналогичному принципу и действуете. Измените вот эту строку:
str = InputBox(«Введите через запятую номера дней недели от 1 до 7», «Ввод значений») На:
где row — это будет номер строки, а col — номер колонки той ячейки, из которой необходимо получать данные.
0 |
PiLLyulk 0 / 0 / 0 Регистрация: 15.08.2018 Сообщений: 30 |
||||||||
20.08.2018, 17:27 [ТС] |
19 |
|||||||
Loya, добрый день. А как убрать MsgBox, который выдает кол-во дней и сделать так что-бы сумма выбранных дней недели попадала в ячейку с функцией? Ну то-есть не понедельник: 2, среда: 2, кол-во рабочих:7, а просто 4 (среды+ понедельники)? Добавлено через 7 часов 14 минут Пока получается такой вариант.
Не могу выбор дней недели сделать аргументом.
Собственно только этого для счастья и не хватает.
0 |
70 / 57 / 24 Регистрация: 06.12.2015 Сообщений: 300 |
|
20.08.2018, 17:34 |
20 |
Не могу выбор дней недели сделать аргументом. А что конкретно не получается? Ошибку какую-то выдает или что?
0 |
Содержание
- Метод WorksheetFunction.WorkDay (Excel)
- Синтаксис
- Параметры
- Возвращаемое значение
- Замечания
- Поддержка и обратная связь
- VBA Excel. Расчет рабочего времени
- Календарь рабочего времени
- Заполнение строки часов
- Поиск ближайшего рабочего дня функцией РАБДЕНЬ (WORKDAY)
- Name already in use
- VBA-Docs / api / Excel.WorksheetFunction.WorkDay.md
- Как определить последний рабочий день месяца(Excel, VBA, PowerQuery)
Метод 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 и обратная связь.
Источник
VBA Excel. Расчет рабочего времени
Расчет рабочего времени за период, ограниченный двумя датами, в течение одного года с помощью кода VBA Excel. Функция для расчета рабочего времени.
Календарь рабочего времени
Для расчета рабочего времени по двум датам нам понадобится производственный мини-календарь на год, состоящий из двух строк:
Создавать такой календарь вручную, не считая протяжку дат, довольно долго и нудно. Поэтому мы создадим производственный мини-календарь программно.
Для создания календаря рабочего времени из кода VBA Excel сначала следует запустить процедуру DaysOfYear, которая заполнит строку дат:
Для создания строки дат потребуется указать только два параметра: год и ячейку, с которой начинается эта строка.
Процедура DaysOfYear запускается из редактора VBA Excel и работает около минуты. Ускорить ее можно, используя массив, который заполняется датами и затем значения его элементов вставляются в диапазон дат.
В конце процедуры диапазону дат присваивается имя, по которому мы будем обращаться к нему в дальнейшем.
Заполнение строки часов
Допустим, нам нужен календарь с пятидневной 40-часовой рабочей неделей, в котором необходимо указать 8 часов для будничных дней и 0 часов — для выходных.
Заполняем строку рабочего времени из кода VBA Excel с помощью процедуры WorkingTimeDay, которая в ячейки строки времени под ячейками с субботой и воскресеньем вставляет 0, а под ячейками с буднями — 8:
Источник
Поиск ближайшего рабочего дня функцией РАБДЕНЬ (WORKDAY)
Простая, но весьма частая задача у многих пользователей Microsoft Excel.
Предположим, что нам необходимо рассчитать срок доставки товара, зная дату отправки и длительность. Поскольку Excel на самом деле хранит даты как числа (количество дней с 1 января 1900 года), то простое сложение легко даст нам предполагаемую конечную дату доставки:
Однако, как видно из предыдущей картинки, нет никакой гарантии, что полученный срок не попадет на выходные, когда доставка не производится. Тогда нужно взять ближайший рабочий день, т.е. следующий понедельник, но какой формулой это лучше сделать?
Первое, что обычно приходит в голову, это конструкция с вложенными проверками дней недели с помощью функций ЕСЛИ (IF) и ДЕНЬНЕД (WEEKDAY) . Что-то типа:
Т.е. если попали на субботу (ДЕНЬНЕД выдал 6 для даты доставки), то прибавляем еще 2 дня, чтобы сдвинуть на следующий понедельник. А если попали на воскресенье, то добавляем еще день. Не самая сложная формула.
На самом деле можно управиться существенно короче и изящнее 🙂
С 2007 года в Excel появилась функция РАБДЕНЬ (WORKDAY) , которая умеет сдвигать исходную дату на заданное количество рабочих дней, причем сдвиг может быть как положительным (в будущее), так и отрицательным (в прошлое). Фишка в том, что если взять предыдущий день от предполагаемой даты доставки и с помощью этой функции добавить к нему один рабочий день, то мы получим либо ту же самую дату (если были будни), либо ближайший понедельник (если доставка выпала на субботу или воскресенье). Что и требуется:
Приятным бонусом идет возможность указать список праздничных выходных дней, которые функция РАБДЕНЬ тоже будет воспринимать как нерабочие помимо суббот и воскресений. Диапазон с праздниками можно задать третьим аргументом:
Легко сообразить, что подобный подход можно использовать и для поиска ближайшего предыдущего, а не следующего рабочего дня.
Источник
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.
Источник
Как определить последний рабочий день месяца(Excel, VBA, PowerQuery)
Проблема получения последнего дня месяца довольно распространена и очень просто решается. Начиная с Excel 2007 можно без всяких доп.манипуляций использовать функцию КОНМЕСЯЦА (EOMONTH) :
=КОНМЕСЯЦА(ТДАТА();0)
=EOMONTH(NOW(),0)
ТДАТА (NOW) — возвращает текущую дату. Вместо неё можно указать любую дату и последняя дата месяца будет возвращена для указанной даты.
Для версий 2003 и ранее для использования КОНМЕСЯЦА (EOMONTH) необходимо для начала подключить надстройку Пакет анализа или же использовать чуть менее понятную формулу:
=ДАТА(ГОД(ТДАТА());МЕСЯЦ(ТДАТА())+1;0)
=DATE(YEAR(NOW()),MONTH(NOW())+1,0)
На самом деле данная формула проста, если разобраться детальнее. Функция ДАТА записывает в ячейку дату, на основании указанного года, месяца и дня. Мы для года берем год от текущей даты, далее берем месяц текущей даты и к месяцу прибавляем 1, чтобы получить следующий месяц. А потом для дня указываем 0, что заставляет Excel сдвинуть первую дату следующего месяца на один день назад. Таким образом и получается последняя дата месяца. Пошагово это выглядит так(если считать, что сегодня «22.10.2017»):
=ДАТА(ГОД(ТДАТА());МЕСЯЦ(ТДАТА())+1;0) =>
=ДАТА(ГОД(«22.10.2017»);МЕСЯЦ(«22.10.2017»)+1;0) =>
=ДАТА(2017;10+1;0) =>
=ДАТА(2017;11;0) здесь уже получится 01.11.2017, но 0 в качестве дня заставляет вернуться на день назад =>
=31.10.2017
Но есть более сложная проблема — получить дату последнего рабочего дня месяца. А это уже не так просто. Встроенных функций(вроде КОНМЕСЯЦА) для этого в Excel нет. А это значит опять придется танцевать с бубном.
Сразу возникает вопрос: а зачем это вообще может потребоваться? Например, для поиска счетов, отгрузка по которым производилась в последний рабочий день месяца, а оплаты(или документы на отгрузку) по некоторым пришли только в начале следующего. Так же такую функцию будет удобно применять для автоматического формирования платежек или накладных, если они должны быть оформлены именно последним рабочим днем месяца.
Чтобы получить именно корректную дату следует так же учесть и тот факт, что есть дни праздничные. И их тоже надо как-то учесть. Для этого я буду использовать отдельный лист Праздники , в столбце А которого записаны праздничные дни на пару лет. Также в этом диапазоне перечислены и все выходные. Сделано для более корректного подсчета дат, т.к. праздники могут быть перенесены, в результате чего рабочими становятся субботы или воскресенья. Если их не учитывать, то расчет будет неверным.
Из спортивного интереса создать такую функцию решил тремя способами:
Последний рабочий день при помощи стандартных функций Excel
В ходе некоторых экспериментов и манипуляций появилась такая формула:
=РАБДЕНЬ(
ЕСЛИ(ДЕНЬНЕД(КОНМЕСЯЦА( B4 ;0);2) B4 ;0);
КОНМЕСЯЦА( B4 ;0)-(ДЕНЬНЕД(КОНМЕСЯЦА( B4 ;0);2)-5));
0; Праздники!$A$2:$A$827)
=WORKDAY(
IF(WEEKDAY(EOMONTH(B4,0),2)
где Праздники!$A$2:$A$827 — ссылка на диапазон дат с праздниками
Здесь я так же использую КОНМЕСЯЦА для быстрого определения последней даты месяца.
Функция ДЕНЬНЕД (WEEKDAY) возвращает номер дня недели для указанной даты и нужна для того, чтобы определить — является последний день недели субботой или воскресеньем. Если нет, то возвращаем дату как есть, если это суббота или воскресенье — то отнимаем от даты либо 1 день, либо 2(если это СБ — то 1, если ВСК — то 2).
И только после этого применяем к полученной дате функцию РАБДЕНЬ (WORKDAY) , которая для последней даты месяца определяет, является ли она праздничной(на основании списка праздников Праздники!$A$2:$A$827 ). Если дата праздничная — то она уменьшается до тех пор, пока не достигнет рабочего дня. РАБДЕНЬ не принимает в расчет выходные, поэтому нам и нужны функции ЕСЛИ и ДЕНЬНЕД, прежде чем применить РАБДЕНЬ.
Однако сразу хочу оговорить, что в конкретно моем случае вычисление выходных дней при помощи ЕСЛИ и ДЕНЬНЕД несколько избыточно, т.к. в диапазоне с праздниками помимо непосредственно праздников у меня уже учтены все выходные дни. Т.е. по сути формула могла бы быть намного проще:
=РАБДЕНЬ(КОНМЕСЯЦА( B4 ;0); 0; Праздники!$A$2:$A$827)
=WORKDAY(EOMONTH(B4,0), 0, Праздники!$A$2:$A$827)
Но я все равно решил именно в статье привести формулу, которая смотрит и на дни недели, т.к. требования могут быть разными.
Т.к. Microsoft все же немного заботится о нас, то для пользователей версий Excel 2010 и более новых, в случае необходимости учитывать день недели прямо в формуле, можно использовать функцию РАБДЕНЬ.МЕЖД:
=РАБДЕНЬ.МЕЖД(КОНМЕСЯЦА(B4;0);0;1;Праздники!$A$2:$A$827)
=WORKDAY.INTL(EOMONTH(B4,0),0,1,Праздники!$A$2:$A$827)
РАБДЕНЬ.МЕЖД[дата; кол-во дней; выходные; праздники]
дата — дата, от которой необходимо отсчитать указанное кол-во дней
кол-во дней — количество дней, которые надо прибавить или отнять(отриц. число — отнимает дни от даты) от указанной даты
выходные — 1 = Суббота и Воскресенье, 2 — Воскресенье и Понедельник и т.д. Полный перечень есть в справке для функции и в выпадающей подсказке к функции при вводе.
праздники — ссылка на диапазон дат с праздниками
Достаточно указать последнюю дату месяца, указать для неё сдвиг на 0 дней, указать тип выходных и ссылку на диапазон дат с праздниками. Все уже сделано и все гораздо проще.
Последний рабочий день при помощи функции пользователя на VBA
Если использование VBA не является для вас проблемой, то можно применить функцию пользователя(UDF) для расчета последнего рабочего дня:
‘————————————————————————————— ‘ Author : The_Prist(Щербаков Дмитрий) ‘ Профессиональная разработка приложений для MS Office любой сложности ‘ Проведение тренингов по MS Excel ‘ http://www.excel-vba.ru ‘ WebMoney — R298726502453; Яндекс.Деньги — 41001332272872 ‘ Purpose: Функция получения последнего рабочего дня на основании указанной даты и списка праздников ‘————————————————————————————— Option Explicit Function ПоследнийРабочийДень(Дата As Date, Optional Праздники As Range = Nothing, Optional СистемныеВыходные As Boolean = False) Dim dd As Date, dres As Date Dim lWeekDay As Long dres = DateSerial(Year(Дата), Month(Дата) + 1, 0) If СистемныеВыходные Then lWeekDay = Weekday(dres, vbUseSystemDayOfWeek) If lWeekDay Alt + F11 ) -создать стандартный модуль(Insert —Module) и в него вставить скопированный текст. После чего функцию можно будет вызвать из Диспетчера функций( Ctrl + F3 ), отыскав её в категории Определенные пользователем (User Defined Functions) .
Синтаксис функции:
=ПоследнийРабочийДень( B4 ;Праздники!$A$2:$A$827;0)
- Дата( B4 ) — непосредственно дата или ссылка на ячейку с датой, последней рабочий день для которой необходимо вычислить. Будет рассчитан последний рабочий день для месяца указанной даты.
- Праздники() — ссылка на диапазон ячеек, содержащих даты праздничных дней.
- СистемныеВыходные(0) — ИСТИНА (TRUE или 1) или ЛОЖЬ (FALSE или 0) . Если указано как ЛОЖЬ, то при вычислении последнего рабочего дня не будут учитываться выходные. В этом случае они обязательно должны быть перечислены в списке Праздники. Если они не перечислены — то все дни недели считаются рабочими, кроме праздников. Если указано как ИСТИНА, то в качестве выходных будут применены те дни, которые установлены для календаря в операционной системе. Для русской локализации это как правило Суббота и Воскресенье.
Последний рабочий день при помощи PowerQuery
Самый экзотический метод. Если еще не знаете что такое PowerQuery — Power Query — что такое и почему её необходимо использовать в работе?.
Для начала необходимо загрузить список праздников.
Если список праздников еще не преобразован в умную таблицу, то на листе Праздники выделяем все ячейки с датами -переходим на вкладку Вставка (Insert) –Таблица (Table) . Снимаем галку с пункта «Таблица с заголовками» —Ок:
Выделяем любую ячейку в созданной таблице праздников -переходим на вкладку Данные (Data или Power Query) и выбираем Из таблицы (From Table) .
Нажимаем в заголовке на значок календаря и в выпадающем списке выбираем тип Дата:
В правой части окна редактора изменяем название запроса(скорее всего там Таблица1) на Праздники:
Переходим на вкладку Главная, раскрываем пункт Закрыть и загрузить и выбираем Закрыть и загрузить в. :
В появившемся окне выбираем Только создать подключение и нажимаем Ок:
Теперь переходим на вкладку Данные(Data) -Получить данные -Из других источников -Пустой запрос. Переходим в расширенный редактор(вкладка Главная —Расширенный редактор):
и вставляем туда следующий текст:
let
dNow = Date.From(DateTime.LocalNow()),
//dNow = Date.FromText(«2017-09-19»),
lastDay = Date.EndOfMonth(dNow),
WeekD = Date.DayOfWeek(lastDay,1),
dd = if WeekD
let
dAdd = value,
select_rows = Table.SelectRows(Праздники, each Record.Field(_, «Дата выходного дня») = dAdd),
count_rows = Table.RowCount(select_rows),
result = Date.AddDays(value,-count_rows)
in
result,
res_d = Table.FromValue(coun_dif(dd))
in
res_d
После этого можно на вкладке Главная нажать Закрыть и загрузить. Будет создан новый лист с одной ячейкой — датой последнего рабочего дня.
Чтобы приведенный запрос работал корректно, необходимо назвать столбец с праздничными датами «Дата выходного дня» . Либо изменить это название в самом запросе.
Если нужен последний рабочий день на конкретную дату, то необходимо убрать первую строку( dNow = Date.From(DateTime.LocalNow()), ) и убрать слеши вначале следующей строки:
let
dNow = Date.FromText(«2017-09-19»),
lastDay = Date.EndOfMonth(dNow),
WeekD = Date.DayOfWeek(lastDay,1),
dd = if WeekD
let
dAdd = value,
select_rows = Table.SelectRows(Праздники, each Record.Field(_, «Дата выходного дня») = dAdd),
count_rows = Table.RowCount(select_rows),
result = Date.AddDays(value,-count_rows)
in
result,
res_d = Table.FromValue(coun_dif(dd))
in
res_d
Если выходные не надо учитывать(чтобы суббота и воскресенье не рассчитывались автоматом в зависимости от дня недели), то запрос будет выглядеть так:
let
dNow = Date.FromText(«2017-09-19»),
dd = Date.EndOfMonth(dNow),
coun_dif = (value as date) as date =>
let
dAdd = value,
select_rows = Table.SelectRows(Праздники, each Record.Field(_, «Дата выходного дня») = dAdd),
count_rows = Table.RowCount(select_rows),
result = Date.AddDays(value,-count_rows)
in
result,
res_d = Table.FromValue(coun_dif(dd))
in
res_d
Реализацию всех приведенных решений можно скачать в приложенном файле
Скачать файл:
ПоследнийРабочийДень.xlsm (50,7 KiB, 614 скачиваний)
Статья помогла? Поделись ссылкой с друзьями!
Источник