Примеры работы с датами (добавление, разность, начало/конец месяца)

Примеры работы с датами (добавление, разность, начало/конец месяца) на языке программирования 1С:Предприятие. Примеры позволяют быстро разобраться в вопросе и использовать код в своих разработках

Базовые операции с датами: добавление и вычитание

// Добавление и вычитание временных интервалов к дате
Процедура ДобавлениеИВычитаниеДаты()

    ТекущаяДата = ТекущаяДата();
    Сообщить("Текущая дата: " + Формат(ТекущаяДата, "ДФ=dd.MM.yyyy HH:MM:SS"));
    
    // Добавление дней
    ДатаПлюс10Дней = ТекущаяДата + 10 * 24 * 60 * 60;
    Сообщить("+10 дней: " + Формат(ДатаПлюс10Дней, "ДФ=dd.MM.yyyy HH:MM:SS"));
    
    // Вычитание дней
    ДатаМинус5Дней = ТекущаяДата - 5 * 24 * 60 * 60;
    Сообщить("-5 дней: " + Формат(ДатаМинус5Дней, "ДФ=dd.MM.yyyy HH:MM:SS"));
    
    // Добавление месяцев
    ДатаПлюс3Месяца = ДобавитьМесяц(ТекущаяДата, 3);
    Сообщить("+3 месяца: " + Формат(ДатаПлюс3Месяца, "ДФ=dd.MM.yyyy"));
    
    // Добавление лет
    ДатаПлюс2Года = ДобавитьМесяц(ТекущаяДата, 24);
    Сообщить("+2 года: " + Формат(ДатаПлюс2Года, "ДФ=dd.MM.yyyy"));
    
    // Добавление часов, минут, секунд
    ДатаПлюс2Часа = ТекущаяДата + 2 * 60 * 60;
    ДатаПлюс30Минут = ТекущаяДата + 30 * 60;
    ДатаПлюс45Секунд = ТекущаяДата + 45;
    
    Сообщить("+2 часа: " + Формат(ДатаПлюс2Часа, "ДФ=dd.MM.yyyy HH:MM:SS"));
    Сообщить("+30 минут: " + Формат(ДатаПлюс30Минут, "ДФ=dd.MM.yyyy HH:MM:SS"));
    Сообщить("+45 секунд: " + Формат(ДатаПлюс45Секунд, "ДФ=dd.MM.yyyy HH:MM:SS"));
    
КонецПроцедуры

Функция ДобавитьМесяц(Дата, КоличествоМесяцев)
    Год = Год(Дата);
    Месяц = Месяц(Дата);
    День = День(Дата);
    
    НовыйМесяц = Месяц + КоличествоМесяцев;
    НовыйГод = Год + Цел((НовыйМесяц - 1) / 12);
    НовыйМесяц = ((НовыйМесяц - 1) % 12) + 1;
    
    // Корректируем день, если он выходит за пределы месяца
    ПоследнийДень = КонецМесяца(Дата(НовыйГод, НовыйМесяц, 1));
    Если День > ПоследнийДень Тогда
        День = ПоследнийДень;
    КонецЕсли;
    
    Возврат Дата(НовыйГод, НовыйМесяц, День, Час(Дата), Минута(Дата), Секунда(Дата));
КонецФункции

Вычисление разности между датами

// Расчет разницы между двумя датами в различных единицах измерения
Процедура РазностьДат()

    ДатаНачала = Дата(2024, 1, 15, 9, 0, 0);
    ДатаОкончания = Дата(2024, 3, 20, 18, 30, 45);
    
    Сообщить("Дата начала: " + Формат(ДатаНачала, "ДФ=dd.MM.yyyy HH:MM:SS"));
    Сообщить("Дата окончания: " + Формат(ДатаОкончания, "ДФ=dd.MM.yyyy HH:MM:SS"));
    
    // Разность в секундах
    РазностьВСекундах = ДатаОкончания - ДатаНачала;
    Сообщить("Разность в секундах: " + РазностьВСекундах);
    
    // Разность в днях
    РазностьВДнях = Цел(РазностьВСекундах / (24 * 60 * 60));
    Сообщить("Разность в днях: " + РазностьВДнях);
    
    // Разность в часах
    РазностьВЧасах = Цел(РазностьВСекундах / (60 * 60));
    Сообщить("Разность в часах: " + РазностьВЧасах);
    
    // Разность в минутах
    РазностьВМинутах = Цел(РазностьВСекундах / 60);
    Сообщить("Разность в минутах: " + РазностьВМинутах);
    
    // Получение разности в формате "X лет Y месяцев Z дней"
    Функция РазностьВГодахМесяцахДнях(Дата1, Дата2)
        Год1 = Год(Дата1);
        Месяц1 = Месяц(Дата1);
        День1 = День(Дата1);
        
        Год2 = Год(Дата2);
        Месяц2 = Месяц(Дата2);
        День2 = День(Дата2);
        
        // Вычисляем разность
        Дней = День2 - День1;
        Месяцев = Месяц2 - Месяц1;
        Лет = Год2 - Год1;
        
        Если Дней < 0 Тогда
            Месяцев = Месяцев - 1;
            // Добавляем количество дней в предыдущем месяце
            ПредыдущийМесяц = Дата2 - День2 * 24 * 60 * 60;
            Дней = Дней + День(КонецМесяца(ПредыдущийМесяц));
        КонецЕсли;
        
        Если Месяцев < 0 Тогда
            Лет = Лет - 1;
            Месяцев = Месяцев + 12;
        КонецЕсли;
        
        Возврат Строка(Лет) + " лет " + Строка(Месяцев) + " месяцев " + Строка(Дней) + " дней";
    КонецФункции
    
    Результат = РазностьВГодахМесяцахДнях(ДатаНачала, ДатаОкончания);
    Сообщить("Разность (годы/месяцы/дни): " + Результат);
    
КонецПроцедуры

Начало и конец месяца, квартала, года

// Получение граничных дат периода: начало/конец месяца, квартала, года
Процедура НачалаИКонцыПериодов()

    ПроизвольнаяДата = Дата(2024, 5, 15, 14, 30, 0);
    Сообщить("Исходная дата: " + Формат(ПроизвольнаяДата, "ДФ=dd.MM.yyyy HH:MM:SS"));
    
    // Начало и конец месяца
    НачалоМесяца = НачалоМесяца(ПроизвольнаяДата);
    КонецМесяца = КонецМесяца(ПроизвольнаяДата);
    
    Сообщить("Начало месяца: " + Формат(НачалоМесяца, "ДФ=dd.MM.yyyy"));
    Сообщить("Конец месяца: " + Формат(КонецМесяца, "ДФ=dd.MM.yyyy"));
    
    // Начало и конец квартала
    НомерКвартала = Цел((Месяц(ПроизвольнаяДата) - 1) / 3) + 1;
    НачалоКвартала = Дата(Год(ПроизвольнаяДата), (НомерКвартала - 1) * 3 + 1, 1);
    КонецКвартала = КонецМесяца(ДобавитьМесяц(НачалоКвартала, 2));
    
    Сообщить("Квартал " + Строка(НомерКвартала) + ": " + 
             Формат(НачалоКвартала, "ДФ=dd.MM.yyyy") + " - " + 
             Формат(КонецКвартала, "ДФ=dd.MM.yyyy"));
    
    // Начало и конец года
    НачалоГода = Дата(Год(ПроизвольнаяДата), 1, 1);
    КонецГода = Дата(Год(ПроизвольнаяДата), 12, 31);
    
    Сообщить("Начало года: " + Формат(НачалоГода, "ДФ=dd.MM.yyyy"));
    Сообщить("Конец года: " + Формат(КонецГода, "ДФ=dd.MM.yyyy"));
    
    // Начало и конец дня
    НачалоДня = НачалоДня(ПроизвольнаяДата);
    КонецДня = КонецДня(ПроизвольнаяДата);
    
    Сообщить("Начало дня: " + Формат(НачалоДня, "ДФ=dd.MM.yyyy HH:MM:SS"));
    Сообщить("Конец дня: " + Формат(КонецДня, "ДФ=dd.MM.yyyy HH:MM:SS"));
    
    // Начало и конец недели (понедельник - воскресенье)
    НачалоНедели = НачалоНедели(ПроизвольнаяДата);
    КонецНедели = КонецНедели(ПроизвольнаяДата);
    
    Сообщить("Начало недели (пн): " + Формат(НачалоНедели, "ДФ=dd.MM.yyyy"));
    Сообщить("Конец недели (вс): " + Формат(КонецНедели, "ДФ=dd.MM.yyyy"));
    
КонецПроцедуры

Функция НачалоНедели(Дата)
    ДеньНедели = ДеньНедели(Дата);
    // Понедельник = 1, Воскресенье = 7
    Сдвиг = ДеньНедели - 1;
    Возврат Дата - Сдвиг * 24 * 60 * 60;
КонецФункции

Функция КонецНедели(Дата)
    Возврат КонецДня(НачалоНедели(Дата) + 6 * 24 * 60 * 60);
КонецФункции

Работа с датами в запросах

// Использование дат в запросах: фильтрация, группировка, приведение типов
Процедура ДатыВЗапросах()

    // Создаем временную таблицу с датами
    ТаблицаДат = СоздатьТаблицуСДанными();
    
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ
    |    Данные.Документ,
    |    Данные.Дата,
    |    
    |    // Начало и конец дня для фильтрации
    |    ВЫРАЗИТЬ(Данные.Дата КАК ДАТА) КАК ДатаБезВремени,
    |    
    |    // Извлечение частей даты
    |    ГОД(Данные.Дата) КАК Год,
    |    МЕСЯЦ(Данные.Дата) КАК Месяц,
    |    ДЕНЬ(Данные.Дата) КАК День,
    |    ЧАС(Данные.Дата) КАК Час,
    |    
    |    // Начало месяца для группировки
    |    НАЧАЛОПЕРИОДА(Данные.Дата, МЕСЯЦ) КАК НачалоМесяца,
    |    КОНЕЦПЕРИОДА(Данные.Дата, МЕСЯЦ) КАК КонецМесяца,
    |    
    |    // Начало квартала
    |    НАЧАЛОПЕРИОДА(Данные.Дата, КВАРТАЛ) КАК НачалоКвартала,
    |    
    |    // Начало года
    |    НАЧАЛОПЕРИОДА(Данные.Дата, ГОД) КАК НачалоГода
    |ИЗ
    |    &ТаблицаДанных КАК Данные
    |ГДЕ
    |    // Фильтрация по дате без времени
    |    ВЫРАЗИТЬ(Данные.Дата КАК ДАТА) = &ДатаФильтра
    |    
    |УПОРЯДОЧИТЬ ПО
    |    Данные.Дата";
    
    // Заполняем таблицу и параметры
    Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаДат);
    Запрос.УстановитьПараметр("ДатаФильтра", Дата(2024, 5, 15));
    
    Результат = Запрос.Выполнить().Выгрузить();
    
    Сообщить("Результаты запроса с группировкой по датам:");
    Для Каждого Строка Из Результат Цикл
        Сообщить(Строка.Документ + " | " + Строка.Дата + 
                 " | Год: " + Строка.Год + 
                 " | Месяц: " + Строка.Месяц + 
                 " | День: " + Строка.День);
    КонецЦикла;
    
КонецПроцедуры

Функция СоздатьТаблицуСДанными()
    Таблица = Новый ТаблицаЗначений;
    Таблица.Колонки.Добавить("Документ");
    Таблица.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
    
    Таблица.Добавить().Документ = "Док-1"; Таблица[0].Дата = Дата(2024, 5, 15, 10, 0, 0);
    Таблица.Добавить().Документ = "Док-2"; Таблица[1].Дата = Дата(2024, 5, 15, 14, 30, 0);
    Таблица.Добавить().Документ = "Док-3"; Таблица[2].Дата = Дата(2024, 5, 16, 9, 0, 0);
    
    Возврат Таблица;
КонецФункции

Циклическая обработка дат (итерация по дням)

// Перебор всех дней в заданном диапазоне и генерация последовательности дат
Процедура ЦиклическаяОбработкаДат()

    ДатаНачала = Дата(2024, 5, 1);
    ДатаОкончания = Дата(2024, 5, 31);
    
    Сообщить("Период с " + Формат(ДатаНачала, "ДФ=dd.MM.yyyy") + 
             " по " + Формат(ДатаОкончания, "ДФ=dd.MM.yyyy"));
    
    // 1. Перебор всех дней в диапазоне
    Сообщить("Все дни месяца:");
    ТекущаяДата = ДатаНачала;
    Пока ТекущаяДата <= ДатаОкончания Цикл
        Сообщить(Формат(ТекущаяДата, "ДФ=dd.MM.yyyy") + " (" + ДеньНеделиСтрокой(ТекущаяДата) + ")");
        ТекущаяДата = ТекущаяДата + 24 * 60 * 60;
    КонецЦикла;
    
    // 2. Генерация массива всех дат периода
    МассивДат = Новый Массив;
    ТекущаяДата = ДатаНачала;
    Пока ТекущаяДата <= ДатаОкончания Цикл
        МассивДат.Добавить(ТекущаяДата);
        ТекущаяДата = ТекущаяДата + 24 * 60 * 60;
    КонецЦикла;
    
    Сообщить("Создан массив из " + МассивДат.Количество() + " дат");
    
    // 3. Фильтрация рабочих дней (понедельник - пятница)
    РабочиеДни = Новый Массив;
    Для Каждого Дата Из МассивДат Цикл
        ДеньНедели = ДеньНедели(Дата);
        Если ДеньНедели >= 2 И ДеньНедели <= 6 Тогда // Пн=2 ... Пт=6
            РабочиеДни.Добавить(Дата);
        КонецЕсли;
    КонецЦикла;
    
    Сообщить("Рабочие дни: " + РабочиеДни.Количество() + " из " + МассивДат.Количество());
    
    // 4. Поиск ближайшего рабочего дня
    ЗаданнаяДата = Дата(2024, 5, 12); // Воскресенье
    БлижайшийРабочий = НайтиБлижайшийРабочийДень(ЗаданнаяДата);
    
    Сообщить("Заданная дата: " + Формат(ЗаданнаяДата, "ДФ=dd.MM.yyyy") + 
             " (" + ДеньНеделиСтрокой(ЗаданнаяДата) + ")");
    Сообщить("Ближайший рабочий день: " + Формат(БлижайшийРабочий, "ДФ=dd.MM.yyyy") + 
             " (" + ДеньНеделиСтрокой(БлижайшийРабочий) + ")");
    
КонецПроцедуры

Функция ДеньНеделиСтрокой(Дата)
    Дни = Новый Массив;
    Дни.Добавить("Воскресенье");
    Дни.Добавить("Понедельник");
    Дни.Добавить("Вторник");
    Дни.Добавить("Среда");
    Дни.Добавить("Четверг");
    Дни.Добавить("Пятница");
    Дни.Добавить("Суббота");
    
    Возврат Дни[ДеньНедели(Дата) - 1];
КонецФункции

Функция НайтиБлижайшийРабочийДень(Дата)
    ТекущаяДата = НачалоДня(Дата);
    
    // Проверяем на 3 дня вперед и 3 дня назад
    Для Сдвиг = 0 По 3 Цикл
        ДатаПлюс = ТекущаяДата + Сдвиг * 24 * 60 * 60;
        ДеньНеделиПлюс = ДеньНедели(ДатаПлюс);
        Если ДеньНеделиПлюс >= 2 И ДеньНеделиПлюс <= 6 Тогда
            Возврат ДатаПлюс;
        КонецЕсли;
        
        ДатаМинус = ТекущаяДата - Сдвиг * 24 * 60 * 60;
        ДеньНеделиМинус = ДеньНедели(ДатаМинус);
        Если ДеньНеделиМинус >= 2 И ДеньНеделиМинус <= 6 Тогда
            Возврат ДатаМинус;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Дата;
КонецФункции

Обработка ошибок при работе с датами

// Безопасное создание дат и корректировка некорректных значений
Процедура БезопаснаяРаботаСДатами()

    // 1. Безопасное создание даты с проверкой
    Функция СоздатьДатуБезопасно(Год, Месяц, День, Час = 0, Минута = 0, Секунда = 0)
        // Корректировка года
        Если Год < 1 Тогда Год = 1; КонецЕсли;
        Если Год > 9999 Тогда Год = 9999; КонецЕсли;
        
        // Корректировка месяца
        Если Месяц < 1 Тогда Месяц = 1; КонецЕсли;
        Если Месяц > 12 Тогда Месяц = 12; КонецЕсли;
        
        // Корректировка дня
        ПоследнийДеньМесяца = День(КонецМесяца(Дата(Год, Месяц, 1)));
        Если День < 1 Тогда День = 1; КонецЕсли;
        Если День > ПоследнийДеньМесяца Тогда День = ПоследнийДеньМесяца; КонецЕсли;
        
        // Корректировка времени
        Час = Мин(Макс(Час, 0), 23);
        Минута = Мин(Макс(Минута, 0), 59);
        Секунда = Мин(Макс(Секунда, 0), 59);
        
        Возврат Дата(Год, Месяц, День, Час, Минута, Секунда);
    КонецФункции
    
    // Примеры некорректных дат
    Сообщить("Корректировка некорректных дат:");
    
    Дата1 = СоздатьДатуБезопасно(2024, 13, 15);   // Месяц 13 -> 12
    Сообщить("13 месяц -> " + Формат(Дата1, "ДФ=dd.MM.yyyy"));
    
    Дата2 = СоздатьДатуБезопасно(2024, 2, 30);    // Февраль не имеет 30 дня
    Сообщить("30 февраля -> " + Формат(Дата2, "ДФ=dd.MM.yyyy"));
    
    Дата3 = СоздатьДатуБезопасно(2024, 4, 31);    // Апрель не имеет 31 дня
    Сообщить("31 апреля -> " + Формат(Дата3, "ДФ=dd.MM.yyyy"));
    
    // 2. Безопасное преобразование строки в дату
    Функция СтрокуВДату(СтрокаДаты, ФорматДаты = "dd.MM.yyyy")
        Попытка
            Возврат Дата(СтрокаДаты);
        Исключение
            Попытка
                // Пробуем разобрать вручную
                Части = СтрРазделить(СтрокаДаты, ".");
                Если Части.Количество() = 3 Тогда
                    День = Число(Части[0]);
                    Месяц = Число(Части[1]);
                    Год = Число(Части[2]);
                    Возврат СоздатьДатуБезопасно(Год, Месяц, День);
                КонецЕсли;
            Исключение
                Возврат Дата(1, 1, 1);
            КонецПопытки;
            Возврат Дата(1, 1, 1);
        КонецПопытки;
    КонецФункции
    
    ДатаИзСтроки = СтрокуВДату("31.02.2024");
    Сообщить("Преобразование '31.02.2024' -> " + Формат(ДатаИзСтроки, "ДФ=dd.MM.yyyy"));
    
    // 3. Валидация даты перед использованием
    Функция ДатаКорректна(ДатаДляПроверки)
        Если Год(ДатаДляПроверки) < 1 Или Год(ДатаДляПроверки) > 9999 Тогда
            Возврат Ложь;
        КонецЕсли;
        
        Месяц = Месяц(ДатаДляПроверки);
        Если Месяц < 1 Или Месяц > 12 Тогда
            Возврат Ложь;
        КонецЕсли;
        
        День = День(ДатаДляПроверки);
        ПоследнийДень = День(КонецМесяца(ДатаДляПроверки));
        Если День < 1 Или День > ПоследнийДень Тогда
            Возврат Ложь;
        КонецЕсли;
        
        Возврат Истина;
    КонецФункции
    
    Попытка
        ТестоваяДата = Дата(2024, 2, 30);
    Исключение
        ТестоваяДата = Дата(1, 1, 1);
    КонецПопытки;
    
    Если ДатаКорректна(ТестоваяДата) Тогда
        Сообщить("Дата корректна");
    Иначе
        Сообщить("Дата некорректна, используйте безопасное создание");
    КонецЕсли;
    
КонецПроцедуры

Функция КонецМесяца(Дата)
    // Возвращает последний день указанного месяца
    // Если дата - произвольное число месяца, возвращает последний день этого месяца
    ГодМесяц = Год(Дата);
    МесяцЧисло = Месяц(Дата);
    СледующийМесяц = ДобавитьМесяц(Дата(ГодМесяц, МесяцЧисло, 1), 1);
    Возврат СледующийМесяц - 24 * 60 * 60;
КонецФункции

Примечания

// Важные особенности работы с датами в 1С:
// 1. В 1С дата хранится как количество секунд с 00:00 01.01.0001
// 2. Для добавления дней используйте Дата + Секунды (день = 86400 секунд)
// 3. Для добавления месяцев используйте функцию ДобавитьМесяц() с корректировкой дня
// 4. Функции НачалоМесяца(), КонецМесяца(), НачалоГода(), КонецГода() - встроенные
// 5. В запросах используйте ВЫРАЗИТЬ(Дата КАК ДАТА) для отсечения времени
// 6. Для группировки используйте НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ/КВАРТАЛ/ГОД)
// 7. При создании даты через конструктор Дата() будьте осторожны - будет ошибка при неверных параметрах
// 8. Для безопасного создания дат реализуйте проверку границ месяца
// 9. Разность дат возвращает количество секунд
// 10. ДеньНедели() возвращает число от 1 (воскресенье) до 7 (суббота)
// 11. При итерации по дням используйте цикл с добавлением 86400 секунд
// 12. Для сложных расчетов (рабочие дни, праздники) создавайте отдельные функции-обработчики

Поделиться с друзьями
Smirnov code
Добавить комментарий