Как исправить ошибку "Дата не может быть записана в базу данных с нулевым смещением дат" в 1С

Системный администратор 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Налоговый учет IT и автоматизация бизнеса
← На главную

При работе с базами данных 1С:Предприятие, размещенными на СУБД MS SQL Server, пользователи и администраторы иногда сталкиваются с крайне специфической ошибкой. В процессе проведения документов (например, счетов-фактур полученных на аванс в конфигурации "Бухгалтерия предприятия") система внезапно прекращает работу и выдает сообщение следующего вида: "Дата '31.03.0001 23:59:59' не может быть записана в базу данных на MS SQL Server с нулевым смещением дат".

Данная проблема способна поставить в тупик даже опытных специалистов, поскольку она может возникать не при явной записи какого-либо объекта в базу данных, а непосредственно во время выполнения запроса в процедуре проведения. В этой статье мы подробно разберем по шагам природу данной ошибки, выясним технические причины ее возникновения на стыке платформы 1С и MS SQL Server, а также рассмотрим практические способы ее решения как на уровне администрирования СУБД, так и на уровне программного кода.

Почему возникает дата "31.03.0001 23:59:59"?

Для того чтобы понять суть проблемы, проанализируем, откуда в системе берется столь странная дата, ведь пользователи очевидно не вводят первый год нашей эры вручную в документах. Источником проблемы является стандартное поведение платформы 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

Теперь выясним, почему эта дата становится критической для MS SQL Server. В СУБД от Microsoft для хранения дат долгое время использовался стандартный тип данных DATETIME. Этот тип данных имеет жесткое физическое ограничение нижнего диапазона: минимально допустимая дата для него — 1 января 1753 года. Любая дата, предшествующая этому значению (включая весь первый год нашей эры и дату 31.03.0001), физически не может быть записана в колонку типа DATETIME.

Для преодоления этого фундаментального противоречия между пустой датой 1С (0001 год) и ограничениями SQL Server (1753 год) разработчики платформы 1С внедрили механизм под названием "Смещение дат" (обычно равное 2000 годам).

Рассмотрим, как работает смещение дат на практическом примере:

До тех пор, пока пустая дата передается в простом запросе на выборку, СУБД может обрабатывать ее внутренними механизмами трансляции 1С. Но ситуация резко меняется, когда в запросе задействованы временные таблицы.

Почему ошибка возникает при выполнении запроса (SELECT), а не при записи документа?

Часто разработчики и администраторы недоумевают: почему база данных успешно записывает документы, но проведение падает на этапе обычного, казалось бы, запроса на чтение данных? Ответ кроется в использовании механизмов временных таблиц.

Когда в тексте запроса используется инструкция ПОМЕСТИТЬ ИмяВременнойТаблицы или менеджер временных таблиц в коде, СУБД SQL Server выполняет реальные физические операции записи:

  1. В системной базе данных tempdb на сервере SQL создается временная таблица с соответствующими типами колонок.
  2. Платформа 1С выполняет команду INSERT INTO для наполнения этой временной таблицы результатами выборки.
  3. В момент выполнения вставки строка, содержащая вычисленное значение 31.03.0001 23:59:59, пытается записаться в поле типа DATETIME временной таблицы.
  4. Поскольку смещение равно 0, SQL Server пытается записать реальный 0001 год, что вызывает мгновенное аварийное завершение транзакции СУБД из-за выхода значения за допустимые пределы (до 1753 года).

Таким образом, даже если результирующая выборка запроса в итоге оказывается пустой, промежуточное помещение данных во временную таблицу вызывает крах операции проведения.

Диагностика проблемы: проверка смещения дат

Прежде чем приступать к исправлению, необходимо убедиться, что причина действительно кроется в нулевом смещении текущей базы данных. Выполнить эту проверку можно несколькими способами.

Если у вас есть доступ к SQL Server Management Studio (SSMS), выполните простой запрос к служебной таблице настроек вашей базы данных:

SELECT [Offset] FROM [_YearOffset]

Проанализируем результат выполнения этого запроса:

Как правильно исправить смещение дат в существующей базе

Важно помнить критическое правило: категорически запрещено изменять значение в таблице _YearOffset напрямую с помощью SQL-запроса UPDATE! Если вы просто принудительно измените 0 на 2000 в СУБД, платформа 1С начнет вычитать 2000 лет из всех уже существующих в базе документов. В результате все ваши рабочие данные "улетят" в далекое прошлое (например, документы от 2024 года превратятся в документы 24 года нашей эры), что полностью разрушит учет.

Единственным правильным, безопасным и штатным способом изменения смещения дат для работающей информационной базы является ее перезапуск через файл резервной копии. Разберем этот процесс подробно по шагам:

  1. Запустите информационную базу в режиме Конфигуратор.
  2. Выполните полную выгрузку информационной базы в файл резервной копии. Для этого перейдите в меню Администрирование — Выгрузить информационную базу... и сохраните файл с расширением .dt.
  3. Зайдите в консоль администрирования серверов 1С:Предприятия и удалите проблемную базу данных (или переименуйте ее, если требуется сохранить копию на сервере).
  4. Создайте новую базу данных на сервере 1С. В окне параметров создания базы обратите особое внимание на поле "Смещение дат". Обязательно установите значение 2000 (в некоторых версиях платформы это значение устанавливается по умолчанию).
  5. Запустите созданную пустую базу в режиме Конфигуратор.
  6. Выполните загрузку ранее выгруженного файла резервной копии через меню Администрирование — Загрузить информационную базу..., выбрав ваш файл .dt.

При загрузке файлов формата .dt платформа 1С выполняет чтение данных в собственном внутреннем формате, абстрагированном от СУБД. В процессе записи данных в новую базу SQL Server платформа автоматически пересчитает все даты с учетом нового смещения 2000. В результате все пустые даты будут корректно сохранены в SQL как 2001 год, а рабочие документы сохранят свои реальные даты.

Программный способ обхода (Best Practice для разработчиков)

Если по каким-то причинам администраторы СУБД не могут оперативно пересоздать базу данных со смещением 2000 (например, база огромного объема, и процедура выгрузки-загрузки .dt займет слишком много времени), разработчик может временно локализовать проблему на уровне кода 1С.

Для предотвращения подобных ошибок в запросах следует избегать вычисления функций периода (таких как КОНЕЦПЕРИОДА или НАЧАЛОПЕРИОДА) над полями и параметрами, которые могут содержать пустые даты. Проанализируем правильный вариант написания конструкции ВЫБОР в запросе:


ВЫБОР 
    КОГДА &ДатаИсходногоСчетаФактуры = ДАТАВРЕМЯ(1, 1, 1) 
        ТОГДА ДАТАВРЕМЯ(1, 1, 1)
    ИНАЧЕ КОНЕЦПЕРИОДА(&ДатаИсходногоСчетаФактуры, КВАРТАЛ) 
КОНЕЦ

При использовании такой конструкции, если параметр &ДатаИсходногоСчетаФактуры окажется пустым, система сразу вернет пустую дату 01.01.0001 в обход вычисления периода. Платформа 1С умеет корректно транслировать чистую пустую дату в SQL Server даже при нулевом смещении, преобразуя ее в минимально возможное системное значение СУБД. Это гарантирует стабильную работу запросов при любых настройках смещения на сервере.

← На главную