Читайте дальше...
Базовые операции с датами: добавление и вычитание
// Добавление и вычитание временных интервалов к дате
Процедура ДобавлениеИВычитаниеДаты()
ТекущаяДата = ТекущаяДата();
Сообщить("Текущая дата: " + Формат(ТекущаяДата, "ДФ=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. Для сложных расчетов (рабочие дни, праздники) создавайте отдельные функции-обработчики








