Получение даты, зная день недели и его порядок в месяце

Программирование - Универсальные функции

Иногда бывает необходимость получить "Первый понедельник месяца" или "Вторую пятницу месяца". Есть несколько способов решения вопроса. Опишу один из них.

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

Один из хороших вариантов решения описан в статье Номер дня недели в месяце.

Мой вариант выглядит следующим образом


// Функция - Получить день недели в месяце
//
// Параметры:
//  Неделя		- Число - Порядковый номер недели в месяце (1, 2, 3, 4)
//  ДеньНедели		- Число - День недели, где 1 - Понедельник, ..., 7 - Воскресенье
//  ЗаданнаяДатаМесяца	- Дата	- Дата месяца, для которой необходимо получить дату дня
// 
// Возвращаемое значение:
// Дата - Если она существует или Неопределено
//
Функция ПолучитьДеньНеделиВМесяце(Неделя, ДеньНедели, ЗаданнаяДатаМесяца)
	
	Результат = Неопределено;
	
	ПервыйДеньМесяца = НачалоМесяца(ЗаданнаяДатаМесяца); 		// 11.09.17 - > 01.09.17
	ПервыйДеньНеделиМесяца = ДеньНедели(ПервыйДеньМесяца);		// 01.09.17 - > 5 (Пятница)
	СмещениеДняНеделиМесяца = ДеньНедели - ПервыйДеньНеделиМесяца;	// 1 - 5 = -4 (Смещение для понедельника)
	
	Если СмещениеДняНеделиМесяца < 0 Тогда
		СмещениеДняНеделиМесяца = 7 + СмещениеДняНеделиМесяца; // если получили отрицательное значение, то прибавляем неделю  7-4=3
	КонецЕсли; 
	
	ИскомаяДатаДня = 7*(Неделя-1) + СмещениеДняНеделиМесяца + 1; // Находим день 7*(1-1) + 3 + 1 = 4 
	
	Попытка
		Результат = Дата(Год(ЗаданнаяДатаМесяца), Месяц(ЗаданнаяДатаМесяца), ИскомаяДатаДня); // Пытаемся преобразовать
	Исключение
	    Результат = Неопределено; // такой даты не существует (Например 7ой понедельник месяца)
	КонецПопытки;
	
	Возврат Результат;
		
КонецФункции

 

 

См. также

Лучшие комментарии
3. Сергей (ildarovich) 5383 13.09.17 12:48 Сейчас в теме
Вот еще вариант:
Функция ПолучитьДатуПоНомерамДня_и_НеделиМесяца(НомерНеделиМесяца, НомерДняНедели, ДатаМесяца)
	
	Возврат НачалоМесяца(ДатаМесяца) 
+ 86400 * (7 * НомерНеделиМесяца - 7 + (НомерДняНедели - ДеньНедели(НачалоМесяца(ДатаМесяца)) + 7) % 7)
	
КонецФункции
В функции, приведенной в статье, мне не нравится "Попытка-Исключение", которую лучше не использовать для относительно простой календарной арифметики, а оставить для более серьезных и сложных случаев. И то, что возвращается в исключении. Если результат функции будет без проверки на неопределено использоваться в выражении, то получится еще одно исключение. А если делать проверку, то она будет еще одной.
Остальные комментарии
1. Александр Крынецкий (echo77) 753 13.09.17 05:41 Сейчас в теме
Из практического применения вспомнилось только как найти последнюю пятницу июля
2. Сергей Лесовой (Synoecium) 272 13.09.17 08:55 Сейчас в теме
запросом проще, имхо:
ВЫБРАТЬ
	ВЫБОР
		КОГДА ДЕНЬНЕДЕЛИ(НАЧАЛОПЕРИОДА(&ЗаданнаяДатаМесяца, МЕСЯЦ)) <= &ДеньНедели
			ТОГДА ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&ЗаданнаяДатаМесяца, МЕСЯЦ), НЕДЕЛЯ, &Неделя - 1), НЕДЕЛЯ), ДЕНЬ, &ДеньНедели - 1)
		ИНАЧЕ ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&ЗаданнаяДатаМесяца, МЕСЯЦ), НЕДЕЛЯ, &Неделя), НЕДЕЛЯ), ДЕНЬ, &ДеньНедели - 1)
	КОНЕЦ КАК ДатаРезультат
4. Erik Nas (987ww765) 20 13.09.17 13:03 Сейчас в теме
(2) Проще, не спорю. Даже привел статью, где рассматривается этот вариант. Просто это другой вариант решения.
3. Сергей (ildarovich) 5383 13.09.17 12:48 Сейчас в теме
Вот еще вариант:
Функция ПолучитьДатуПоНомерамДня_и_НеделиМесяца(НомерНеделиМесяца, НомерДняНедели, ДатаМесяца)
	
	Возврат НачалоМесяца(ДатаМесяца) 
+ 86400 * (7 * НомерНеделиМесяца - 7 + (НомерДняНедели - ДеньНедели(НачалоМесяца(ДатаМесяца)) + 7) % 7)
	
КонецФункции
В функции, приведенной в статье, мне не нравится "Попытка-Исключение", которую лучше не использовать для относительно простой календарной арифметики, а оставить для более серьезных и сложных случаев. И то, что возвращается в исключении. Если результат функции будет без проверки на неопределено использоваться в выражении, то получится еще одно исключение. А если делать проверку, то она будет еще одной.
5. Erik Nas (987ww765) 20 13.09.17 13:16 Сейчас в теме
(3) Шикарное решение. Снимаю шляпу. Сам бы я не додумался до такого(
6. Oleg Space (spacecraft) 13.09.17 13:53 Сейчас в теме
(3) интересный алгоритм. Только не правильно отрабатывает на параметрах вне диапазона. Точнее если указать параметры меньше допустимого для данного месяца.
Пример:
ДатаМесяц = Дата(2017,1,1);
НомерНеделиМесяца = 1;
НомерДняНедели = 1;
Получим '02.01.2017'.
В большую сторону отрабатывает.
Это конечно проблема передачи корректных данных, но забавно.
7. Сергей (ildarovich) 5383 13.09.17 14:27 Сейчас в теме
(6) А мне кажется, что результат верный, ведь спрашивается дата первого понедельника месяца (как я понял задачу). Это и есть второе января.
8. Oleg Space (spacecraft) 13.09.17 14:39 Сейчас в теме
(7) если так подходить к задаче, тогда верно. Только получается, что начало первой недели больше конца первой недели. Логический нонсенс.
9. Сергей (ildarovich) 5383 13.09.17 16:10 Сейчас в теме
(8) Да, согласен, наверное, мне нужно было по другому функцию и параметры называть...ближе к формулировке задачи в анонсе.
Оставьте свое сообщение