При работе с базами данных 1С:Предприятие, размещенными на СУБД MS SQL Server, пользователи и администраторы иногда сталкиваются с крайне специфической ошибкой. В процессе проведения документов (например, счетов-фактур полученных на аванс в конфигурации "Бухгалтерия предприятия") система внезапно прекращает работу и выдает сообщение следующего вида: "Дата '31.03.0001 23:59:59' не может быть записана в базу данных на MS SQL Server с нулевым смещением дат".
Данная проблема способна поставить в тупик даже опытных специалистов, поскольку она может возникать не при явной записи какого-либо объекта в базу данных, а непосредственно во время выполнения запроса в процедуре проведения. В этой статье мы подробно разберем по шагам природу данной ошибки, выясним технические причины ее возникновения на стыке платформы 1С и MS SQL Server, а также рассмотрим практические способы ее решения как на уровне администрирования СУБД, так и на уровне программного кода.
Для того чтобы понять суть проблемы, проанализируем, откуда в системе берется столь странная дата, ведь пользователи очевидно не вводят первый год нашей эры вручную в документах. Источником проблемы является стандартное поведение платформы 1С при обработке незаполненных (пустых) реквизитов типа "Дата".
В системе 1С:Предприятие пустая дата представляется как 01.01.0001 00:00:00 (начало первого года нашей эры). Ошибка, как правило, проявляется при выполнении сложных запросов, в которых разработчики используют стандартные функции работы с периодами. Рассмотрим конкретный пример фрагмента запроса, вызывающего сбой:
ВЫБОР
КОГДА Реквизиты.ИсправлениеСобственнойОшибки
И КОНЕЦПЕРИОДА(Реквизиты.Дата, КВАРТАЛ) > КОНЕЦПЕРИОДА(&ДатаИсходногоСчетаФактуры, КВАРТАЛ)
ТОГДА НАЧАЛОПЕРИОДА(&ДатаИсходногоСчетаФактуры, КВАРТАЛ)
ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1)
КОНЕЦ КАК КорректируемыйПериод
Если анализируемый документ не является исправлением или корректировкой, параметр &ДатаИсходногоСчетаФактуры передается в запрос как пустая дата — то есть 01.01.0001 00:00:00. Когда СУБД начинает вычислять выражение КОНЕЦПЕРИОДА(&ДатаИсходногоСчетаФактуры, КВАРТАЛ), платформа транслирует это в расчет последнего момента первого квартала первого года нашей эры. Математически это значение равняется именно 31.03.0001 23:59:59.
Теперь выясним, почему эта дата становится критической для MS SQL Server. В СУБД от Microsoft для хранения дат долгое время использовался стандартный тип данных DATETIME. Этот тип данных имеет жесткое физическое ограничение нижнего диапазона: минимально допустимая дата для него — 1 января 1753 года. Любая дата, предшествующая этому значению (включая весь первый год нашей эры и дату 31.03.0001), физически не может быть записана в колонку типа DATETIME.
Для преодоления этого фундаментального противоречия между пустой датой 1С (0001 год) и ограничениями SQL Server (1753 год) разработчики платформы 1С внедрили механизм под названием "Смещение дат" (обычно равное 2000 годам).
Рассмотрим, как работает смещение дат на практическом примере:
01.01.0001) сохраняется в таблицах SQL Server как 01.01.2001, что абсолютно корректно воспринимается СУБД. При чтении данных платформа выполняет обратную операцию — вычитает 2000 лет.До тех пор, пока пустая дата передается в простом запросе на выборку, СУБД может обрабатывать ее внутренними механизмами трансляции 1С. Но ситуация резко меняется, когда в запросе задействованы временные таблицы.
Часто разработчики и администраторы недоумевают: почему база данных успешно записывает документы, но проведение падает на этапе обычного, казалось бы, запроса на чтение данных? Ответ кроется в использовании механизмов временных таблиц.
Когда в тексте запроса используется инструкция ПОМЕСТИТЬ ИмяВременнойТаблицы или менеджер временных таблиц в коде, СУБД SQL Server выполняет реальные физические операции записи:
tempdb на сервере SQL создается временная таблица с соответствующими типами колонок.INSERT INTO для наполнения этой временной таблицы результатами выборки.31.03.0001 23:59:59, пытается записаться в поле типа DATETIME временной таблицы.Таким образом, даже если результирующая выборка запроса в итоге оказывается пустой, промежуточное помещение данных во временную таблицу вызывает крах операции проведения.
Прежде чем приступать к исправлению, необходимо убедиться, что причина действительно кроется в нулевом смещении текущей базы данных. Выполнить эту проверку можно несколькими способами.
Если у вас есть доступ к SQL Server Management Studio (SSMS), выполните простой запрос к служебной таблице настроек вашей базы данных:
SELECT [Offset] FROM [_YearOffset]
Проанализируем результат выполнения этого запроса:
0 — это подтверждает, что база данных была создана без смещения дат, и это является главной причиной падения проведения документов.2000 — смещение настроено корректно, и причину ошибки следует искать в непосредственном повреждении данных (наличии реальных "битых" дат в таблицах).Важно помнить критическое правило: категорически запрещено изменять значение в таблице _YearOffset напрямую с помощью SQL-запроса UPDATE! Если вы просто принудительно измените 0 на 2000 в СУБД, платформа 1С начнет вычитать 2000 лет из всех уже существующих в базе документов. В результате все ваши рабочие данные "улетят" в далекое прошлое (например, документы от 2024 года превратятся в документы 24 года нашей эры), что полностью разрушит учет.
Единственным правильным, безопасным и штатным способом изменения смещения дат для работающей информационной базы является ее перезапуск через файл резервной копии. Разберем этот процесс подробно по шагам:
.dt..dt.При загрузке файлов формата .dt платформа 1С выполняет чтение данных в собственном внутреннем формате, абстрагированном от СУБД. В процессе записи данных в новую базу SQL Server платформа автоматически пересчитает все даты с учетом нового смещения 2000. В результате все пустые даты будут корректно сохранены в SQL как 2001 год, а рабочие документы сохранят свои реальные даты.
Если по каким-то причинам администраторы СУБД не могут оперативно пересоздать базу данных со смещением 2000 (например, база огромного объема, и процедура выгрузки-загрузки .dt займет слишком много времени), разработчик может временно локализовать проблему на уровне кода 1С.
Для предотвращения подобных ошибок в запросах следует избегать вычисления функций периода (таких как КОНЕЦПЕРИОДА или НАЧАЛОПЕРИОДА) над полями и параметрами, которые могут содержать пустые даты. Проанализируем правильный вариант написания конструкции ВЫБОР в запросе:
ВЫБОР
КОГДА &ДатаИсходногоСчетаФактуры = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА ДАТАВРЕМЯ(1, 1, 1)
ИНАЧЕ КОНЕЦПЕРИОДА(&ДатаИсходногоСчетаФактуры, КВАРТАЛ)
КОНЕЦ
При использовании такой конструкции, если параметр &ДатаИсходногоСчетаФактуры окажется пустым, система сразу вернет пустую дату 01.01.0001 в обход вычисления периода. Платформа 1С умеет корректно транслировать чистую пустую дату в SQL Server даже при нулевом смещении, преобразуя ее в минимально возможное системное значение СУБД. Это гарантирует стабильную работу запросов при любых настройках смещения на сервере.