Домашнее задание №3 базового курса
Третье задание по 0-му блоку базового курса.
Для выполнения рекомендуется изучить следующие главы 0-го блока.
Глава 11. Программный код
Глава 12. Примитивные типы данных
Глава 13. Контекст исполнения кода
Глава 14. Объектная техника
Глава 15. Сервисные средства по написанию кода
Глава 16. Основные объекты конфигурации.
Глава 17. Виды учета.
К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте — залогиньтесь. Если Вы оплачивали курс, у Вас активирован токен доступа, Вы залогинены, но Вы видите эту запись — напишите нам на e-mail поддержки.
Что-то сделал, вроде как работает:
Процедура ВыполнитьНажание(Команда)
ВыходныеДни=Новый Структура;
Для Год=2010 по 2020 Цикл
КоличествоРабочихДней=ПолучитьКоличествоРабочихДней(Год);
ВыходныеДни.Вставить("Год"+Формат(Год,"ЧГ="),КоличествоРабочихДней);
КонецЦикла;
Сообщить(ВыходныеДни.Год2014);
КонецПроцедуры
&НаКлиенте
Функция ПолучитьКоличествоРабочихДней(Год)
МассивПраздников=Новый Массив;
МассивПраздников.Добавить(Дата(Год,1,1));
МассивПраздников.Добавить(Дата(Год,2,23));
МассивПраздников.Добавить(Дата(Год,3,8));
РабочихДней=0;
КонецГода=КонецДня(Дата(Год,12,31));
ТекущийДень=НачалоДня(Дата(Год,1,1));
Пока ТекущийДень<=КонецГода Цикл
Если МассивПраздников.Найти(ТекущийДень)=Неопределено И ДеньНедели(ТекущийДень)<6 тогда
РабочихДней=РабочихДней+1;
КонецЕсли;
ТекущийДень=ТекущийДень+86400;
КонецЦикла;
Возврат РабочихДней;
КонецФункции
Насчет кода без цикла, по-моему это бред т.к. обычно требуется получение подобных данных за произвольный период, а не ровно за год.
ДЗ №3 выполнил
Дз 3 сделал, немного повозился со структурой и оптимизацией. Код стандартный в два цикла.
Понравился код Elisey’я – наверное будет самым быстрым ;).
Домашнее задание решил двумя способами:
1. Одним циклом “Пока”.
2. Рекурсией – но рекурсия 10 лет подряд не может отработать, пришлось по два года :)
1 способ:
Структура=Новый Структура;
Дата1=Дата(“20100101”);
Дата2=ДобавитьМесяц(Дата1,12*10);
СчДни=0;
Пока Дата1<Дата2 Цикл
Если ДеньНедели(Дата1)<6
И НЕ(День(Дата1)=1 И Месяц(Дата1)=1)
И НЕ(День(Дата1)=23 И Месяц(Дата1)=2)
И НЕ(День(Дата1)=8 И Месяц(Дата1)=3)
Тогда
СчДни=СчДни+1;
КонецЕсли;
Если Дата1=НачалоДня(КонецГода(Дата1)) Тогда
Структура.Вставить("Год"+Формат(Год(Дата1), "ЧГ=0"),СчДни);
Сообщить(""+Год(Дата1)+" Дни="+СчДни);
СчДни=0;
КонецЕсли;
Дата1=Дата1+60*60*24;
КонецЦикла;
Сообщить(Структура.Год2014);
второй большой, выкладывать, наверное не стоит…
ДЗ №3 выполнил
ДЗ № 3 Выполнил, двумя способами – расчетный по количеству недель и перебором.
ДЗ сделал, но пока решение самому не нравится, еще подумаю маленько..
ДЗ №3 выполнил
ДЗ №3 выполнил. Очень интересно видеть разнообразные подходы к решению задачи у других участников.
Ну коли пошли листинги, выложу и свой на всеобщее обсуждение.
Процедура ВычислитьРабочиеДни(ДатаНачала,ДатаОкончания)
// Вставить содержимое обработчика.
ВыходныеДни = Новый Структура;
Нач = НачалоГода(ДатаНачала);
Кон = КонецГода(ДатаОкончания);
ДлинаДня = 24*60*60;
ТекДата = Нач;
ТекГод = Год(ТекДата);
РабочихДней = 0;
Пока ТекДата <= Кон Цикл
// проверка на праздники
День = День(ТекДата);
Месяц= Месяц(ТекДата);
НомерДняНедели = ДеньНедели(ТекДата);
Праздник = (День = 1 и месяц = 1) или (День=23 и Месяц=2) или (День=8 и Месяц=3);
Праздник = Праздник и НомерДняНедели < 6;
Если ТекГод Год(ТекДата) Тогда
ВыходныеДни.Вставить(“Год_” + Формат(ТекГод,”ЧГ=”), РабочихДней);
Сообщить(“Год “+ТекГод+”: “+РабочихДней);
ТекГод = Год(ТекДата);
РабочихДней = 0;
КОнецЕсли;
РабочийДень = НомерДняНедели < 6 и не Праздник;
РабочихДней = РабочихДней+?(РабочийДень,1,0);
ТекДата=НачалоДня(ТекДата+ДлинаДня);
КонецЦикла;
ВыходныеДни.Вставить("Год_" + Формат(ТекГод,"ЧГ="), РабочихДней);
Сообщить("Год "+ТекГод+": "+РабочихДней);
КонецПроцедуры
ДЗ №3 сделано. Использовал 2 цикла.
ДЗ-3 выполнил, проблем не возникло
Домашнее задание сделано.
Решил “в лоб”. Вроде проблем нет.
НачальныйГод = 2010;
ВыходныеДни = Новый Структура;
ДеньПериода = НачалоГода(ТекущаяДата());
КонечныйГод = 2101;
КоличествоРабочих= 0;
ТекущийГод = 2010;
Пока ТекущийГод < КонечныйГод цикл
Если Год(ДеньПериода) ТекущийГод тогда //Перейдем к следующему году
ВыходныеДни.Вставить(“Год”+СтрЗаменить(Строка(ТекущийГод),” “,””),КоличествоРабочих);
ТекущийГод = Год(ДеньПериода);
Сообщить(Строка(ТекущийГод) + ” ” + СТрока(КоличествоРабочих));
КоличествоРабочих = 0;
КонецЕсли;
Если (ДеньНедели(ДеньПериода) > 5)
или ((День(ДеньПериода) = 1) и (Месяц(ДеньПериода) = 1))
или ((День(ДеньПериода) = 23) и (Месяц(ДеньПериода) = 2))
или ((День(ДеньПериода) = 8) и (Месяц(ДеньПериода) = 3)) тогда
Иначе
КоличествоРабочих = КоличествоРабочих + 1;
КонецЕсли;
ДеньПериода = ДеньПериода + 60*60*24;
КонецЦикла;
Домашнее задание №3 выполнил.
Не знаю насколько оптимально. Брал два цикла: Внешний по годам, начиная со следующего от текущего года. Внутренний по дням. Все выходные и праздничные дни находил используя функцию формат с передачей туда интересующей даты:
Если не(Формат(ТекущийДень,”ДФ=””дддд”””) = “суббота”
или Формат(ТекущийДень,”ДФ=””дддд”””) = “воскресенье”
или Формат(ТекущийДень,”ДФ=””дд ММММ”””) = “08 марта”
или Формат(ТекущийДень,”ДФ=””дд ММММ”””) = “01 января”
или Формат(ТекущийДень,”ДФ=””дд ММММ”””) = “23 февраля”) Тогда
ЧислоРабочихДней = ЧислоРабочихДней+1;
КонецЕсли;
Год в структуру возвращал функцией год. При этом пришлось убирать символ отделяющий тысячи от сотен.
ВыходныеДни.Вставить(“Год”+СтрЗаменить(ТекущийГод, Символ(КодСимвола(ТекущийГод, 2)),””), ЧислоРабочихДней);
Получил результат:
2011 год – 258 рабочих дней.
2012 год – 259 рабочих дней.
2013 год – 259 рабочих дней.
2014 год – 260 рабочих дней.
2015 год – 259 рабочих дней.
2016 год – 258 рабочих дней.
2017 год – 258 рабочих дней.
2018 год – 258 рабочих дней.
2019 год – 259 рабочих дней.
2020 год – 261 рабочих дней.
Что получил то получил :-)
Наверно его можно сделать и лучше.
Подумал и решил выложть все решение. Уместилось в одной процедуре:
Процедура КнопкаВыполнитьНажатие(Кнопка)
ГодНачалаОтсчета = Число(Формат(Год(КонецГода(ТекущаяДата))+1),”ЧГ=0″));
ВыходныеДни = Новый Структура();
Для ТекущийГод = ГодНачалаОтсчета По ГодНачалаОтсчета + 10 Цикл
ТекущийДень = НачалоГода(Дата(ТекущийГод,01,01,00,00,00));
ЧислоРабочихДней = 0;
Пока ТекущийДень <= КонецГода(Дата(ТекущийГод,01,01,00,00,00)) Цикл
Если не(Формат(ТекущийДень,"ДФ=""дддд""") = "суббота"
или Формат(ТекущийДень,"ДФ=""дддд""") = "воскресенье"
или Формат(ТекущийДень,"ДФ=""дд ММММ""") = "08 марта"
или Формат(ТекущийДень,"ДФ=""дд ММММ""") = "01 января"
или Формат(ТекущийДень,"ДФ=""дд ММММ""") = "23 февраля")
Тогда
ЧислоРабочихДней = ЧислоРабочихДней+1;
КонецЕсли;
ТекущийДень=ТекущийДень+3600*24;
КонецЦикла;
ВыходныеДни.Вставить("Год"+СтрЗаменить(ТекущийГод, Символ(КодСимвола(ТекущийГод, 2)),""), ЧислоРабочихДней);
Сообщить(СтрЗаменить(ТекущийГод, Символ(КодСимвола(ТекущийГод, 2)),"") +" год – "+Строка(ЧислоРабочихДней)+" рабочих дней.");
КонецЦикла;
Сообщить(ВыходныеДни.Год2014);
КонецПроцедуры
ДЗ №3 выполнил.
ДЗ №3 выполнил, праздники сохранял в соответствии.
сделал, но много кода опять, буду оптимизировать…
Задачка работает. Сделала без затей – в циклах
ДЗ №3 выполнила.
ДЗ №3 выполнил. Даже без цикла удалось обойтись…
Задание №3 выполнил без сильных затруднений.
Немного повозиться пришлось. Перебирать дни счиатю не оптимизированный вариант. Сам сделал один цикл с перебором по годам. Вот что получилось –
КонечныйГод = НачальныйГод + КоличествоЦиклов-1;
ВыходныеДни = Новый Структура();
Для Счетчик = НачальныйГод По КонечныйГод Цикл
Если (Счетчик % 4 = 0) и (не (счетчик % 100 = 0) или (счетчик %400)=0) Тогда
Високосный = Истина;
Иначе
Високосный = Ложь;
КонецЕсли;
КоличествоВыходных = 52 * 2 + 1 + ?(Високосный и ДеньНедели(Формат(Счетчик,”ЧГ=0″)+”0102000001″)>5,1,0) +
?(ДеньНедели(Формат(Счетчик,”ЧГ=0″)+”0223000001″)<=5,1,0)+
?(ДеньНедели(Формат(Счетчик,"ЧГ=0")+"0308000001")<=5,1,0);
КоличествоРабочих = ?(Високосный, 366, 365) – КоличествоВыходных;
ВыходныеДни.Вставить("Год"+Формат(Счетчик,"ЧГ=0"),КоличествоРабочих);
КонецЦикла;
1. Сначала определяем високосность года, на кратность 4, 100 и 400
2. вычисляем количество выходных по логике 52 полных недели умножаем на два выходных, если первое января хоть выходной, хоть нет, надо его прибавить, и если в високосном году 2 января выпадает на выходной то его надо тоже прибавить еще прибавляем праздничные 23 февраля и 8 марта если они выпадают на рабочие дни.
3. Вычисляем рабочие дни в зависимости от выходных и от високосности года.
ДЗ №3 выполнил
Задание интересное. Со структурами не работал, пришлось поразбираться.
В цикле по годам фрагмент такой:
КонецГода = Дата(Год,12,31);
ДнейВГоду = ДеньГода(КонецГода);
НедельВГоду = Цел(ДнейВГоду/7);
ВыходныхДней = НедельВГоду*2;
ДнейНеполнНедели = ДнейВГоду – НедельВГоду*7;
Для й=1 По ДнейНеполнНедели Цикл
ВыходныхДней = ВыходныхДней + ЭтоВыходной( Дата(Год,1,й));
КонецЦикла;
ВыходныхДней = ВыходныхДней + ЭтоВыходной( Дата(Год,1,1));
ВыходныхДней = ВыходныхДней + ЭтоВыходной( Дата(Год,2,23));
ВыходныхДней = ВыходныхДней + ЭтоВыходной( Дата(Год,3,8));
РабочихДней = ДнейВГоду-ВыходныхДней;
Сделано. Проблемы были только с ключом структуры из-за неразрывного пробела.
Сделал!
Тоже без циклов.
На заметку – полезная функция НеделяГода()
Выполнил ДЗ. Результаты проверил.Выполнил подсчет рабочих дней через метод Найти(ВыходныеДни,ДеньНедели(ПроверяемаяДата)).
ДЗ №3 выполнил
ДЗ №3 выполнила. Все нормально.
ДЗ №3 выполнил.
ОК.
Проблем с ДЗ №3 не возникло
Сделано!
&НаКлиенте
Функция ПодсчетРабочихДнейВГоду(Дата)
Год = Год(Дата);
ДеньНеделиНачГода = ДеньНедели(Дата(Год,01,01));
ДнейВГоду = ДеньГода(Дата(Год,12,31));
ВыходныхВПраздничныеДни = ?(ДеньНеделиНачГода >5, 1, ?(ДеньНеделиНачГода = 5,ДнейВГоду – 365,0))
+ ?(ДеньНеделиНачГода <= 5, 1, 0)
+ ?(ДеньНедели(Дата(Год,02,23)) <= 5, 1, 0)
+ ?(ДеньНедели(Дата(Год,03,08)) <= 5, 1, 0);
КоличествоВыходных = Цел(ДнейВГоду/7)*2+ВыходныхВПраздничныеДни;
Возврат ДнейВГоду – КоличествоВыходных;
КонецФункции
Что-то Вы малость перемудрили. Сравнил результат Вашей функции с “классическим” результатом по циклу, прогонял до 2100 года. В 2028, 2056 и 2084 году обнаружены расхождения. По “классике” получается 258 рабочих дней, у Вас 259.
Да, вы правы, не учел один нюанс. Вот как должен быть приблизительно расчет выходных дней:
ВыходныхВПраздничныеДни = ?(ДеньНеделиНачГода >5, 1 + (ДнейВГоду – 365)*(ДеньНеделиНачГода = 6) , ?(ДеньНеделиНачГода = 5,ДнейВГоду – 365,0))
+ ?(ДеньНеделиНачГода <= 5, 1, 0)
+ ?(ДеньНедели(Дата(Год,02,23)) <= 5, 1, 0)
+ ?(ДеньНедели(Дата(Год,03,08)) <= 5, 1, 0);
Сделано
Сделано. Результаты совпадают с вышеприведенными. Использовал два вложенных цикла (по годам и по дням). Для ключа структуры применил
Ключ = “Год”+Формат(Год, “ЧГ=0”);
Даже не знаю, что тут можно ещё выжать. Но подождём решения профессионалов.
сделал:
Год 2 020 – 261
Год 2 019 – 259
Год 2 018 – 258
Год 2 017 – 258
Год 2 016 – 258
Год 2 015 – 259
Год 2 014 – 260
Год 2 013 – 259
Год 2 012 – 259
Год 2 011 – 258
Год 2 010 – 258
Затруднений не было, но собственный вариант с циклами не нравится. Жду решения от гуру)
ДЗ №3 сделано.
Сделал.
ДЗ сделал. Ну наверное в лоб (через циклы). Сегодня подумаю над оптимизацией. Но как и у Сергея Калмыкова (выше по посту) есть проблемы:
(я решал на платформе 8.2.10.77)
Для соответствия все работает как и должно:
ВыходныеДни = Новый Соответствие;
Год = 2010;
КолРабочихДней = 258; //к примеру
ВыходныеДни.Вставить(“Год”+Год,КолРабочихДней); //данная строчка работает
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = “” + ВыходныеДни.Получить(“Год”+Год);//и эта тоже
Сообщение.Сообщить();
А вот для структуры работает, но не совсем:
ВыходныеДни = Новый Структура();
Год = 2010;
КолРабочихДней = 258;
ВыходныеДни.Вставить(“Год2010”,КолРабочихДней);//вот так будет работать
//ВыходныеДни.Вставить(“Год”+Год,КолРабочихДней);//а вот так нет
//Ошибка: “Задано неправильное имя атрибута структуры”
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = “” + ВыходныеДни.Год2010;//вот так работает
//Сообщение.Текст = “” + ВыходныеДни[“Год”+Год]; //а вот так нет. Ошибка: “Поле объекта не обнаружено (Год2 010)”
Сообщение.Сообщить();
Начал разбираться. Посмотрите какое поле не обнаружено: (Год2 010)
Т.е. между “Год2” и “010” вроде существует пробел.
Попробовал поискать пробел в ключе:
…….
Год = 2010;
Ключ = “Год”+Год;
Если Найти(Ключ,” “)>0 Тогда
Сообщить(“Нашел”);//Пробел не нашел
КонецЕсли;
…….
Хорошо, попробовал задать другой ключ для структуры (с добавлением меньшего количества цифр)
Например:
ВыходныеДни = Новый Структура();
Год = 110; //Число из 3 цифр
КолРабочихДней = 258;
ВыходныеДни.Вставить(“Год”+Год,КолРабочихДней);//Данная строка заработала
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = “” + ВыходныеДни[“Год” + Год];//И эта строка тоже стала работать
Сообщение.Сообщить();
Интересно, а на других платформах (более поздних релизах) такой “глюк” тоже присутствует?
Конечно можно как-то извратится и сделать, но если для соответствий работает, то наверное должно работать и для структур.
А еще вопрос: где должна компилироваться функция по расчету рабочих дней, на клиенте или на сервере (вроде к базе данных не обращаемся, но ресурсы по вычислению задействуются)?
Никакого глюка в данном релизе нет. Цитирую описание коллекции Структура из Синтакс-Помощника: “Представляет собой коллекцию пар КлючИЗначение. При этом ключ может быть только строковым и должен удовлетворять требованиям, предъявляемым к именованию переменных встроенного языка.” Поскольку числовая переменная (Год, в данном случае) по-умолчанию форматируется пробелом для разделения разрядов, он же (пробел) сохраняется и при преобразовании в строку. Стало быть ключ структуры не удовлетворяет правилу именования переменных. Выход: предварительно форматировать число функцией Формат (в предыдущих постах есть примеры).
Если Найти(Ключ,» «)>0 Тогда
Сообщить(«Нашел»);//Пробел не нашел
КонецЕсли;
Вышеприведенный код не находил пробел поскольку при форматировании используется символ неразрывного пробела (системный набор значений Символы.НПП). Его и нужно было искать.
Спасибо! Теперь понял, что существует не только пробел, но и не разрывный пробел (Символы.НПП)
….
Год = Строка(2010);
Ключ = “Год”+Год;
Если Найти(Ключ,Символы.НПП)>0 Тогда
Сообщить(“Нашел”); //нашел
КонецЕсли;
……
А в соответствии работает, т.к. ключ там может с любым типом данных.
Вывод: надо вовремя ложится спать и почаще читать форум, а то “глюки” кажутся везде!!!
В результате – цикл только только по годам. Остальное – по если.
Сначала была попытка заполнить таблицу значений на все 10-ть лет – более универсально, получаем календарь, но, выходит за рамки задания, да и явно не оптимально.
Потом – счетчик по годам и внутри счетчик с определением конца года по текущей дате – запутывлась в секундах дат. Потом решила внутренний счетчик вообще убрать.
Сделано!