Форум Кладовочки АЛьФ`а

Общие вопросы => 7.7 => Тема начата: Харлампий Дымба от 23 ноября 2024, 16:53

Название: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 23 ноября 2024, 16:53
ПолучитьПустоеЗначение("Дата") + (4713 + 2024) * 365 + Цел((4713 + 2024) / 4) - Цел((4713 + 2024) / 100) + Цел((4713 + 2024) / 400)  = 23.11.2024
Так долго хотел спросить почему так - но пока собирался, уже сам разобрался.
В сети мне как-то не попадались обсуждения про пустую дату в 7.7. Может плохо искал, а может это общеизвестно и банально.
Но если кому-то вдруг будет интересно, распишу потом как-нибудь.
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Злоп от 24 ноября 2024, 12:03
Распиши
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: АЛьФ от 25 ноября 2024, 09:26
"Пустая дата" в 7.7. - это 01.01.1753. Так было в старом MSSQL, оттуда и в 1С залетело.
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Злоп от 25 ноября 2024, 14:17
ПолучитьПустоеЗначение("Дата")-(ТекущаяДата()-500*365) = -2278140
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 16 декабря 2024, 18:55
    Всё что написано ниже - это просто  перечисление вещей, которые меня когда зацепили, заинтриговали, заставили задуматься и разбираться. На абсолютную и полную истину не претендую - это мои измышления, наблюдения и выводы. Некоторые вещи, которые были неочевидными для меня, могут оказаться банальными и само собой разумеющимися. Некоторые вещи к которым я пришёл, могли быть получены гораздо более простыми шагами, особенно при должной теоретической подготовке в астрономии и программировании. У меня нет исходников 1С, так что приведённые алгоритмы работы программы - мои измышления, тщательно (не всегда) проверенные и подтверждённые экспериментально.
Выражения для простоты повествования буду приводить примерно так как они выглядят при использовании Сервис-Табло.

Погнали:
Как-то задумался, а Дата(0) и ПолучитьПустоеЗначение(«Дата») это одно и то же?
?(ПолучитьПустоеЗначение("Дата")=Дата(0), "да", "нет") = "да"Да, это одно и тоже. А если какая-нибудь ересь в кавычках?
?(ПолучитьПустоеЗначение("Дата")='какая-нибудь ересь', "да", "нет") = "да"Да, и это тоже. И кстати ЖКК говорит, что неопределенная дата задается как '00.00.00':
?(ПолучитьПустоеЗначение("Дата")='00.00.00',"да", "нет") = "да"Имеем 3 варианта получения неопределенной даты: ПолучитьПустоеЗначение("Дата"), Дата(0), '  .  .  '. Далее для простоты буду использовать в основном Дата(0).

Разберёмся с кавычками: преобразование даты в одинарных кавычках происходит последовательно по двум маскам:
'NN?NN?NNNN*'
'NN?NN?NN*'
Т.е 23 ноября 2024 можно записать как '23-11/24' или '23а11б2024вгдеёж', ну или более привычное '23.11.2024'. Если с помощью этих двух масок не получилось валидной даты - дате присваивается неопределенное значение.
    Заметим также, что при использовании второй маски первые две цифры года будут определены с помощью года начала рабочего столетия, установленного в меню «Сервис - Параметры». В случае записи года двумя цифрами, будет взят ближайший подходящий год строго больший года начала рабочего столетия. 1С строго бдит за текущей датой, и год начала рабочего столетия всегда находится в диапазоне [ДатаГод(ТекущаяДата())-99,ДатаГод(ТекущаяДата())]. При любом изменении текущего года в Windows (база открыта под бой курантов) на соответствующее число лет сдвигается и год начала рабочего столетия. По умолчанию год начала рабочего столетия устанавливается на 60 лет назад: в ДатаГод(ТекущаяДата())-60.
Чтобы не было проблем с преобразованием дат в зависимости от настроек пользователя желательно писать дату с указанием года 4мя цифрами, а не 2мя: '23.11.2024'.

С одинарными кавычками разобрались. Пару слов о ПолучитьПустоеЗначение(<Тип>). Чтобы получить пустую дату, тип можно задавать не только строкой «Дата», но и объектом метаданных, имеющим тип «Дата»:
ПолучитьПустоеЗначение(Метаданные.Константа(«ДатаЗапретаРедактирования»))либо видом субконто, имеющим тип «Дата»:
ПолучитьПустоеЗначение(ВидСубконто.ДатаДохода)
Далее рассмотрим два варианта метода Дата(). Первая функция преобразования даты:
Дата(<Год>, <Месяц>, <Число>)
Напомню описание: преобразует переданные в качестве числовых параметров Год, Месяц, Число в значение типа 'Дата'. Год указывается 4-хзначным числом (вместе с веком). Возвращает значение типа 'Дата'. Параметры:
<Год> - числовое выражение.
<Месяц> - числовое выражение.
<Число> - числовое выражение.
Вроде всё понятно:
Дата(2024,11,23)='23.11.2024'Но строковые значения параметров метод тоже принимает. Я так понимаю, это поведение характерно для большинства методов 1С - там где параметр задан базовым типом, можно использовать и число, и дату, и строку:
Дата("2024","11","23")='23.11.2024'
Дата(2024,Дата(11),23)= '23.11.2024'
Дата("абв","+1г1е","  23ёж")='23.01.0000'
Видимо, значения параметров преобразовываются по формуле:
ПарамПреоб = Число(СокрЛП(Парам))
Отрицательные числа 1С тут не принимает. Полученная дата будет проверена на количество месяцев и дней в месяце. Но! Всё заведомо хорошо только с датами, лежащими в диапазоне [01.01.0001;31.12.9999]. А вот даты, которые возвращает эта функция для Год>9999 могут быть очень занимательными:
Дата(12345,6,7) = '60.50.1234'
Это происходит потому, что Дата() получает результат так:
преобразует значения параметров: ПарамПреоб = Число(СокрЛП(Парам));
делает контроль значений числа (1..31) и месяца (1..12), а также контроль их взаимоувязки (31 июня), а в случае 29 февраля ещё и контроль високосности года;
делает Месяц = Прав("00"+Месяц,2) и Число = Прав("00"+Число,2);
если СтрДлина(Год)<4, то делает Год=Прав("0000"Год,4);
складывает всё в одну строку ДатаСтрокой = Лев(ГодПреоб+МесяцПреоб+ЧислоПреоб,8).
Проведя эти замечательные преобразования с Дата(12345,6,7) получим такое внутреннее представление даты: Лев("12345"+"06"+"07",8)= "12345060", т.е. 60е число 50го месяца 1234 года.

С этим пожалуй, закончим, мы подошли к героине опуса - функции Дата(<Параметр>), про которую ЖКК говорит следующие:
Описание: Преобразовать параметр в дату.
Описание параметров: <Параметр> -  числовое выражение
Пример: ДатаРожд = Дата('06.03.1958');
Заметили, что в описании параметр числовой, а в примере типа «Дата»? Но нет же смысла писать Дата('06.03.1958'), если можно написать '06.03.1958'. И в типовых от 1С такое использование можно пересчитать по пальцам одной руки. А вот встречающееся в типовых Дата(0) - уже интереснее, и используется чаще - для того, чтобы получить пустое значение типа "Дата".
Проверим:
"!"+дата(0)+"!" = !  .  .  !Хорошо, тут понятно. А вот интересно, что такое Дата(1)?
Дата(1) = '12.31.-471'Странная какая-то дата. Вроде похожа на дату, но неправильная какая-то: месяц и число местами поменяны? Смотрим Дата(2):
Дата(2) = '12.31.-471'То же самое. Ну отлично, значит какой-то мусор идёт просто - видимо пишется какая-то одна неправильная дата. Проверим:
?(Дата(1)=Дата(2), "да", "нет") = "нет"Дата одна, но она разная? Интересно. Ещё играемся:
"!"+дата(-1)+"!" = !  .  .  ! Дата(-1) - пустая. Равна Дата(0)?
?(Дата(-1)=Дата(0), "да", "нет") = "нет"Не равна. И все другие отрицательные даты, хоть и не равны друг другу, визуализируются как пустые.
Вернемся к положительным:
?(Дата(5)=Дата(0)+5, "да", "нет") = "да"
?(Дата(5)=Дата(2)+3, "да", "нет") = "да"
Т.е. число в параметре - это числовое представление даты. Почему же тогда Дата(5) опять визуализируется как Дата(0)?:
Дата(5) = '12.31.-471'Пробуем дальше и вдруг:
Дата(7) = '13.31.-471'
Дата(8) = '20.31.-471'
Дата(9) = '20.31.-471'
Сдвинулось. И замерло опять до:
Дата(17) = '21.31.-471'Сейчас, когда выше я уже описал похожее поведение у функции Дата(<Год>, <Месяц>, <Число>), легче понять, что происходит. Но изначально я долго игрался со счётчиком, пытаясь понять принцип получения возвращаемой даты.

Все оказалось просто: первая цифра месяца - это четвертая цифра года. Вторая цифра месяца - первая цифра месяца. Первая цифра числа - вторая цифра месяца. Вторая цифра числа - первая цифра числа. А вот второй цифры числа в записи нет - отрезана.
Тогда  Дата(1) = '12.31.-471' - это '2Х.11.-4713'. И из того, что первый сдвиг идет на Дата(7) = '3Y.11.-4713' следует, что Y=0, т.е Дата(7) = '3Y.11.-4713'а cтало быть Дата(1) на 6 дней раньше и равна '24.11.-4713'. А значит,
Дата(0) = '23.11.-4713'
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 16 декабря 2024, 18:59
Ну конечно! Нет, от российского ПО я бы ждал расчёт от православного сотворения мира (1 марта 5508 г. до н.э.), но учитывая что 1С написана на C - всё логично. Теперь нам понадобится немножко нужной теории:

Для расчета даты пользуемся номером юлианского дня (далее JDN) с поправкой времени, используем пролептический григорианский календарь с астрономической нумерацией лет. Расшифрую:
Юлианский календарь подразумевает начало отсчета с 01.01.4173г.  до н.э.. и високосные года сначала каждые 3, а потом 4 года.

Григорианский календарь подразумевает поправку на столетние високосные года (каждый 4й год високосный, каждый 100й год невисокосный, каждый 400й - високосный).

Пролептический календарь подразумевает, что все даты в прошлом приводятся по текущим правилам - григорианский календарь был введён недавно: в Испании 04.10.1582г. (первые осознали), в Британской империи - 02.09.1752г. (запомним, чуть ниже пригодится), в России - 31.01.1918г. (суровую постреволюционную зиму Петрограда Ленин волевым росчерком пера сократил аж на 2 недели).
 
Эта поправка на високосные года григорианского календаря задним число привела к изменению даты начала отсчета на 24.11.4174г. до н.э.

Ну а так как после 1 года до н.э. настал 1 год н.э., то есть нулевого года не было, то оказалось очень неудобно считать разницу между годами, да и високосные года до н.э оказались не на месте - 1м, 5м, 9м и т.д. Поэтому для расчетов используется астрономическая нумерация лет, где положительные года совпадают с нашей нумерацией, нулевому году соответствует 1 г. до н.э, минус первому соответствует 2й год до н.э и т.д. Тогда 24.11.4174г. до н.э. будет записан как '24.11.-4173'.

Под поправкой времени подразумеваю следующее: номер юлианского дня считается в днях, прошедших от полудня 12:00 '24.11.-4713', но чтобы не заморачиваться со временем 1С считает от полуночи 24:00 '23.11.-4713', т.е нулевой день будет:
   Дата(0) - 23 ноября 4714 г. до н.э.

Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 16 декабря 2024, 19:10
Преобразование календарной даты к номеру дня JDN в 1С можно сделать  формуле:
    НомерДняJDN = Цел(1461*(Год+4800+Цел((Месяц-14)/12))/4)
    +Цел(367*(Месяц-2-12*Цел((Месяц-14)/12))/12)
    -Цел(3*Цел((Год+4900+Цел((Месяц-14)/12))/100)/4)
    +День-32075;
Ну или получить уже готовый расчет из 1С:, который можно использовать в своих конфигурациях:
НомерДняJDN = ТекущаяДата()-Дата(0)
Обратное преобразование из JDN в календарную дату я воспроизвести не смог, но могу сказать, что в 1С оно корректно работает только в диапазоне лет от 1 до 9999. В датах позже 9999 года после преобразования во внутреннее представление годы начинают съезжать в месяца и числа по описанному выше сценарию. В датах до н.э появляются забавные артефакты - нелепые добавленные даты и пропущенные существующие. Например:
Дата(1721059)  = '30.12.-001' //всё хорошо
Дата(1721060) = '00.01.0000' //нелепая дата вместо '31.12.-001'
Дата(1721061) = '01.01.0000 '//всё хорошо
Дата(1720329) = '31.12.-003' //всё хорошо
Дата(1720330)  = '00.01.-002' //нелепая добавленная
Дата(1720331)  = '01.01.-002' //всё хорошо
А вот пропущенная дата:
Дата(1721425) = '30.12.0000' //всё хорошо
Дата(1721426) = '01.01.0001' //пропущена '31.12.0000'
Очень интересный момент в том, что представление этой пропущенной даты  '31.12.0000' = '01.01.0001'. То есть для 1С это разные представления одной и той же даты. Возможно это сделано, чтобы JDN корректно считалось в нашей эре, ведь в нормальном счете нулевая дата - 24 ноября, а в 1С - 23 ноября, так как расчет JDN в нашей эре съехал из-за поправки на время (помните, полдень перенесли на полночь?).
Ладно, с этим разобрались. Посмотрим теперь другие функции работы с датой.

Значение дат-констант, т.е переменных полученных в результате операций с объектами типа «Дата» - присвоении, арифметических действий, получении результатов функции, возвращающих тип «Дата» хранятся, видимо, в числовом выражении JDN. Поэтому промежуточные результаты, в которых JDN принимает огромное или отрицательное значение не оказывают влияние на конечный результат. Например, сложение и вычитание дат работает по принципу: привели к JDN, вычли-прибавили, привели обратно к календарной дате. Т.е. несмотря на то, что в первом случае в промежуточном результате будет дат меньше чем Дата(0) оба выражения отработают одинаково:
'23.11.2024'-123456789+123456789 = '23.11.2024'
'23.11.2024'+123456789-123456789 = '23.11.2024'

Чего не скажешь о случае, когда промежуточные результаты будут сохранятся в реквизитах. При сохранении значений в базе значение будет приведено к внутреннему представлению и отрицательные значение потеряются:
Дат1 = '23.11.2024' - 123456789; // тут получим отрицательный JDN Дата(-120996151)
Константа.ДатаЗапретаРедактирования = Дат1; //при записи Дата(-120996151) преобразуется в Дата(0)
Дат1 = Константа.ДатаЗапретаРедактирования + 123456789; // тут получим уже '02.01.3333' = Дата(0)+123456789
Упомянем на будущее один момент, который надо учитывать при приведении ко внутреннему представлению - работу с нелепыми датами:
ЗначениеВСтрокуВнутр() и ЗначениеВстроку() преобразует нелепую дату Дата(1721060) = '00.01.0000' в зависимости от того как она передана:
'00.01.0000' -> "        " (8 пробелов);
Дата(1721060) -> "00000100".

Методы ДатаГод(), ДатаМесяц(), ДатаЧисло() - возвращают числа полученные соответственно из первых 4 цифр, 5й и 6й, 7й и 8й внутреннего представления числа.
Например, для Дата(1) = '24.11.-4173' внутреннее представление будет "-4713112", тогда:
ДатаГод()=-471, ДатаМесяц()=31, ДатаЧисло()=12
Для 7 июня 12345г., записанного как Дата(12345,6,7) внутреннее представление будет "12345060", тогда:
ДатаГод()=1234, ДатаМесяц()=50, ДатаЧисло()=60
Для нелепых дат результат будет зависит от того, как они передаются. Например, для нелепой даты Дата(1721060) = '00.01.0000' получим:
ДатаМесяц('00.01.0000') = 0 //передали через одинарные кавычки, т.е. 8 пробелов
ДатаМесяц(Дата(1721060)) =1 //передали через результат функции, т.е. "00000100"
ДатаМесяц(1721060)  = 1 //передали через число.

Метод НомерДняНедели() - это остаток от деления НомерДняJDN % 7  + 1
НомерДняНедели(Дата(-1)) = 7 //работает и с датами до начала отсчета
НомерДняНедели(2460638) = 6 //дату '23.11.2024' можно передать и числом JDN.

Метод НомерДняГода()
НомерДняГода('23.11.2024')  = 328 //все нормально
НомерДняГода(2460638) = 328 //передать JDN тоже можно
НомерДняГода('01.01.0000') = 1//все верно
НомерДняГода('00.01.0000') = 2//забавно, ведь это предыдущая дата: '00.01.0000' = '01.01.0000' -1, а не следующая
НомерДняГода(Дата(12345,6,7)) = 4058367 //гм, многовато
Попробуем разобраться с последним примером. Логично предположить, что для получения номера дня года 1С из JDN текущей даты вычитает JDN конца предыдущего года. Ведь так гораздо удобнее, чем по костяшкам считать число дней в прошедших месяцах. Год получаем из ДатаГод() - т.е. первые четыре цифры, и для 12345 года это будет .. 1234, таким образом, конец предыдущего года это '31.12.1233' и его JDN равен 2171769. Для Дата(12345,6,7) JDN равен 6230136. Итого получаем 6230136 - 2171769  = 4058367. Да, алгоритм подобрали верно.

Аналогично работает метод НомерНеделиГода() - вычисляем разницу между JDN конца предыдущего года и JDN текущей датой. Делим на 7 и округляем в большую сторону. Если НомерДняНедели() конца предыдущего года не равен 7 (год начался не с понедельника), то добавляем ещё 1 неделю.
НомерНеделиГода(Дата(12345,6,7)) = 579768 //  т.е 4058367 / 7 = 579766.714.., округлим вверх и добавим 1.
Методы НачНедели() и КонНедели() тоже работают через остаток от деления JDN на 7, так как Дата(0) - понедельник.
НачНедели =  JDN - JDN % 7
КонНедели = JDN - JDN % 7 + 7

Методы НачГода() и КонГода() работают через получение внешнего представления даты - то есть будут нормально работать с датами от 0001 до 9999 года. Для годов ранее 0000 оба метода вернут значение Дата(-1). Для пустой даты оба метода вернут Дата(0). Для годов позже 9999 оба метода обрежут года под первые четыре цифры. Год 0000 выделяется тем, что, как мы ранее установили '31.12.0000' и '01.01.0001' с точки зрения 1С  - это одно и то же, поэтому КонГода() для нулевого года вернёт дату '01.01.0001', в то время как НачГода() отработает нормально.

Методы НачКвартала(), КонКвартала(), НачМесяца(), КонМесяца() работают абсолютно аналогично. И также косячат с нелепыми датами нулевого года:
НачКвартала('01.01.0000'-1) =01.01.0000 //помним - в 1С есть дата Дата(1721060) ='00.01.0000'
Метод ДобавитьМесяц(<Дата>,<ЧислоМесяцев>). Параметр <Дата> не может быть типа «Число» (но может быть строкой или датой). Число добавляемых/вычитаемых лет = Цел (ЧислоМесяцев / 12), но с поправкой на то, что 1С неправильно возвращает целую часть отрицательных чисел, так что если ЧислоМесяцев<0, то дополнительно вычтем единицу. Метод возвращает Дата(0), если получились отрицательные года. День числа ограничен сверху с учетом номера месяца и високосности года. И, так как функция работает с внутренним представлением, то она тоже даёт артефакты со сдвигом с годами после 9999:
ДобавитьМесяц('31.01.9999',13) = 22.00.1000; //здесь 29.02.10000 ДобавитьМесяц('31.01.9999',13+100*12) = 22.00.1010; //здесь 28.02.10100
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 16 декабря 2024, 21:49
4я часть - справочная, просто список функций, которые работают с числом как с датой:

Присвоение - работает
Спр.ДатаЗакрытия=2460676;// '31.12.2024'
Опер.ДатаОперации=2460676;// '31.12.2024'
Рег.ДатаПартии=2460676;// '31.12.2024'
Док.ДатаДок=2460676;// '31.12.2024'

УстановитьТАна - не работает
УстановитьТАпо - не работает
РассчитатьРегистрыНа - не работает
РассчитатьРегистрыПо - не работает
УстановитьЗначениеВПодборе - не понимаю как пользоваться

Последовательность::Установить - не работает
Последовательность::Сравнить - не работает
Последовательность::Проверить - не работает

Периодический::ДатаЗнач
Периодический::ЗначениеНаДату
Периодический::ВыбратьЗначения
Периодический::НайтиЗначение

Константа::УстановитьАтрибут
Константа::Получить
Константа::Установить

Справочник::УстановитьАтрибут
Справочник::НайтиПоРеквизиту
Справочник::ВыбратьЭлементыПоРеквизиту - практически не работает именно так как описал здесь (https://forum.dorex.pro/index.php?topic=160.0) - то есть, первый элемент выбирает, а следующие нет - видимо какая-то дополнительная проверка идет после каждого перепозиционирования указателя выборки
Справочник::ИспользоватьДату - работают все три варианта
Справочник::УстановитьОтбор - не работает
Справочник::Получить
Справочник::Установить

Документ::УстановитьАтрибут
Документ::НайтиПоНомеру
Документ::ВыбратьДокументы
Документ::ВыбратьПодчиненныеДокументы
Документ::ВыбратьПоНомеру
Документ::ВыбратьПоЗначению(<Дата1>,<Дата2>,<ИмяОтбора>,<Знач>) для параметров <Дата1>,<Дата2> - работает, для параметра <Знач> - не работает
Документ::УстановитьРеквизитСправочника(<ЭлементСправочника>,<НазваниеРеквизита>,<Значение>,<ДатаУстановки>,) для параметра <Значение> - работает, для параметра <ДатаУстановки> - не работает
ЖурналДокументов::УстановитьИнтервал

Регистры::РассчитатьРегистрыНа - не работает
Регистры::РассчитатьРегистрыПо - не работает
Регистр::УстановитьАтрибут
Регистр::ВыбратьДвижения
Регистр::УстановитьФильтр
Регистр::УстановитьЗначениеФильтра
Регистр::ДвижениеПриход
Регистр::ДвижениеРасход
Регистр::Движение
Регистр::Остаток
Регистр::СводныйОстаток - не работает
Регистр::Остатки
Регистр::СводныеОстатки - не работает
Регистр::ИспользоватьПериод - не проверял
Регистр::Итог - не проверял
Регистр::Итоги - не проверял
Регистр::СводныйИтог - не проверял
Регистр::СводныеИтоги - не проверял
Регистр::ВыбратьДвиженияСОстатками - не разобрался как работает с датой

Операция::ВыбратьОперации
Операция::ВыбратьОперацииСПроводками - работают оба варианта
Операция::ВыбратьПоЗначению - работает и для указания периода и для указания значения отбора
ЖурналОпераций::УстановитьИнтервал
ЖурналОпераций::УстановитьОтбор
ЖурналПроводок::УстановитьИнтервал
ЖурналПроводок::УстановитьОтбор - не работает

БухгалтерскиеИтоги::ПериодД
БухгалтерскиеИтоги::ПериодКВ - не работает, переданное число трактуется как номер квартала
БухгалтерскиеИтоги::ПериодКВН - не работает, аналогично
БухгалтерскиеИтоги::ПериодМ - не работает, переданное число трактуется как номер месяца
БухгалтерскиеИтоги::ПериодМНК - не работает, аналогично
БухгалтерскиеИтоги::ПериодМНГ - не работает, аналогично
БухгалтерскиеИтоги::Рассчитать
БухгалтерскиеИтоги::ВыполнитьЗапрос
БухгалтерскиеИтоги::ПолучитьПериод

Календарь::УстановитьАтрибут - не понимаю как пользоваться
Календарь::ВыбратьДаты
Календарь::Автозаполнение
Календарь::ПолучитьДату


Праздники::УстановитьАтрибут - не понимаю как пользоваться
Праздники::Новый
Праздники::Удалить
Праздники::ВыбратьДаты

ЖурналРасчетов::НачалоПериодаПоДате
ЖурналРасчетов::КонецПериодаПоДате
ЖурналРасчетов::ПериодПоДате
ЖурналРасчетов::ОписательПериода
ЖурналРасчетов::ВвестиРасчет
ЖурналРасчетов::ВвестиРасчетНаОсновании
ЖурналРасчетов::ВыбратьЗаписи
ЖурналРасчетов::ВыбратьПериод
ЖурналРасчетов::ВыбратьЗаписиПоОбъекту
ЖурналРасчетов::ВыбратьПериодПоОбъекту
ЖурналРасчетов::УстановитьРеквизит() - не работает для предопределенных ДатаНачала и ДатаОкончания, но работает с пользовательскими реквизитами журнала расчетов типа "Дата"

ТаблицаЗначений::= присвоение значений работает, если тип колонки задан ("Дата")
ТаблицаЗначений::УстановитьЗначение - работает, если тип колонки задан ("Дата")
ТаблицаЗначений::НайтиЗначение - не работает

Запрос::Период с по - работает, если задан переменными запроса, а не значениями
Запрос::Получить работает и для предопределенных группировок и для реквизитов типа дат. Если указана предопределенная группировка День/Неделя/Месяц, то указываем номер дня начало месяца/недели - даже если период запроса не включает этот день.
Запрос (Условие В): не работает (например, вхождение в список чисел номеров дат)
Запрос (Условие =): не работает


Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 16 декабря 2024, 21:58
С методами разобрались, теперь пару слов о хранении дат.
Независимо от варианта хранения (DBF/SQL) будут одинаково работать ЗначениеВСтрокуВнутр(), ЗначениеВСтроку(), ЗначениеВФайл() и СохранитьЗначение(). При их использовании пустые даты: и реквизиты, и переменные, и значения таблицах значений или списках значений - будут преобразованы в 8 пробелов.

В DBF базе дата хранится в виде строки в формате «ГГГГММДД». Для Дата(0) внутреннее представление - 8  пробелов «        ».  Все даты меньше Дата(0) при сохранении будут приведены к Дата(0). Для дат 01.01.0000 до 31.12.1999 будет гарантирована корректность при сохранении (2 исключения). А вот даты вне этого диапазона в процессе сохранения будут приведены к пустой дате и сохранены как 8 пробелов.
Исключение 1: Дата(1721425) в написании '31.12.0000' будет преобразована в '01.01.0001'.
Исключение 2 Дата(1721060) в написании '00.01.0000' будет преобразована Дата(0).

Что касается SQL - не специалист. Используемые в старых версиях (до SQL Server 2008) типы хранения дат (DateTime, smallDataTime и Date?) не позволяли записывать даты раньше 01.01.1753г. Выше уже писал, что начиная именно с этого года все текущие календарные представления дат в Британской империи гарантировано совпадали с тогдашним их представлением. Чего не скажешь про предыдущие даты, так что их ничтоже сумняшеся «отменили» в первых версиях SQL. Таким образом, пустая дата в таблице SQL в 1С это "1753-01-01 00:00:00.000", отбор по пустой дате в прямых запросах, если правильно помню, '17530101'.
Любые даты по 01.01.1753 включительно будут приведены к пустой дате в момент записи значения в соответствующую таблицу SQL. Есть определенные особенности: так как значения констант типа «Дата» хранятся в строковом внутреннем представлении, то ограничение DateTime на них не  распространяется. Даты документов тоже хранятся в составной строке DATE_TIME_IDDOC. А вот реквизиты справочников типа «Дата» или даты периодических реквизитов будут занулены.
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 17 декабря 2024, 00:04
В завершение немного практического смысла:
По мне, из всех этих простынь следует, что на уровне работы с данными 1С не использует UNIX-время, так что проблему 2038 вполне можно обойти.
Ставим в Windwos текущую дату на 4 года раньше реальной (в целом всё равно, но так удобнее високосный 2040 год будет соблюсти), потом можно будет на 8 лет откатить и тд.
Меняем пользователю рабочую дату:
Процедура ПриНачалеРаботыСистемы()
РабочаяДата(ТекущаяДата()+4*365+1);
НачалоСтандартногоИнтервала("Год");//ну или как нравится
КонецСтандартногоИнтервала(РабочаяДата());//ну или как нравится
..
КонецПроцедуры
Ну и собственно, всё. Вполне рабочий вариант для терминалки под ДБФ.
Допускаю, что могут быть боли с компонентами, лицензированием, удобством, и всякими онлайн-сервисами - но тут надо уже в конкретных задачах смотреть.
Про SQL не скажу - надо потестировать.

ИТОГО
Пустая дата - ПолучитьПустоеЗначение(«Дата») - это - 23 ноября 4714 г. до н.э.;
1С использует пролептический григорианский календарь и числовое представление даты в виде юлианского номера дня;
Все даты с '01.01.0001' по '31.12.9999' обрабатываются корректно (кроме некоторых сохранений в SQL дат ранее '02.01.1753')
Пустая дата при сохранении в DBF таблицах - в полях типа «Дата» будет записано 8 пробелов;
Пустая дата при сохранении в SQL - '01.01.1753';
Многие функции позволяют использовать числовое значение даты.
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Djelf от 17 декабря 2024, 06:41
Цитата: Харлампий Дымба от 17 декабря 2024, 00:04Допускаю, что могут быть боли с компонентами, лицензированием, удобством, и всякими онлайн-сервисами - но тут надо уже в конкретных задачах смотреть.
Будут не просто боли, а очень большие боли. Интернет без синхронизации времени работает очень хреново.
Впрочем, простенькое решение есть: https://1progs.ru/runasdate/
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Djelf от 19 декабря 2024, 18:31
Мне, честно говоря, не понятно как это вобще работает...
Вот код в type32.dll (восстановленный Гидрой, сделанной жуткой и очень злобной АНБ)
void __thiscall CDate::CDate(CDate *this,int param_1,int param_2,int param_3) {
  int iVar1;
  /* 0x1570  2  ??0CDate@@QAE@HHH@Z */
  iVar1 = MakeJDate(param_1,param_2,param_3);
  this->m_Date = iVar1;
  return;
}
Как можно заметить, дата в формате int32 т.е. должна быть проблеме 2038 подвержена, но работает и 2048 и т.п.
Где-то заглушка/преобразование int32 в uint32 в коде зашита, иначе эту работоспособность объяснить сложно.
Т.е. вполне возможено, что предварительный сдвиг даты, при запуске клюшек, сработает так нам хочется, но это надо проверять загодя, на виртуалках, и проверять очень тщательно.
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 19 декабря 2024, 23:31
Полный нуб.
Думаю, что MakeJDate возвращает не секунды, а дни. То есть тот самый пресловутый номер дня JDN. В таком случае int32 нам хватит до конца света.
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Злоп от 20 декабря 2024, 00:20
Если простыми словами для нубов: клюшки будут жить вечно?
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Харлампий Дымба от 20 декабря 2024, 11:21
Цитата: Злоп от 20 декабря 2024, 00:20Если простыми словами?
Предварительно - на стыке десятого и одиннадцатого тысячелетия ожидаются проблемы (год - только 4 цифры), надо будет задуматься о переходе.

Что касается ближайшего будущего, то возможно
Цитата: Djelf от 19 декабря 2024, 18:31но это надо проверять
платформа спокойно будет работать со сдвигом даты.
Ближе к Дате Х, лет через 8-10, надо будет посмотреть, какая актуалка в каждом конкретном случае понадобится и как она будет работать.
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Злоп от 20 декабря 2024, 12:52
Цитата: Харлампий Дымба от 20 декабря 2024, 11:21Ближе к Дате Х, лет через 8-10,
если этого не делать сейчас, то к тому времени некому будет. не подхватит никто флаг из рук знаменосца...
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Djelf от 20 декабря 2024, 18:26
Я об этом и писал выше, т.е. обмануть можем, это не сложно, но что-то точно сломается
- видимо mshttp, мой карик и т.п., там нужна синхронизауия времени
Возможно еще что-то есть: возможно в sql базах, в dbf вроде не должно.
Вариантов слишком много, лучше подождать до 2035г, возможно, тогда сдохнет либо Ишак, либо Подишах...
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Злоп от 28 апреля 2025, 14:26
Цитата: АЛьФ от 25 ноября 2024, 09:26"Пустая дата" в 7.7. - это 01.01.1753. Так было в старом MSSQL, оттуда и в 1С залетело.

а в более новых скулях пустая дата как? так же?
Название: Re: Дата NULL в 7.7 - сегодня
Отправлено: Djelf от 28 апреля 2025, 14:36
Цитата: Злоп от 28 апреля 2025, 14:26а в более новых скулях пустая дата как? так же?
Такие особенности не должны меняться, иначе кирдык будет всем программам на новой версии сервера.