Вверх ↑
Ответов: 4664
Рейтинг: 767
#1: 2017-06-06 10:35:34 ЛС | профиль | цитата
В общем, я тут покопался, и сделал модификацию компонента DateConvertor, чтобы исправить выявленные мной недостатки. Нужно обсудить эти недостатки.

DateConvertor mod 2017-06-30.zip


Скриншот:


В существующей реализации

1) Функция XXXToStrFmt не работает, если дата меньше 01.01.1601
2) Если дата меньше 13.02.1901 20:45:52, то в формате Unix её невозможно представить 32-битным числом. Происходит усечение значения и получается бяка.
3) Для HeapIntToDateUnix используется одна и та же функция, что и для DateReal. Она выдаёт результат в DateReal, затем конвертирует его в DateUnix. В приведенном на скриншоте примере результат соответствует примерно 01.01.0001 00:02:30. А эту дату нельзя представить в 32-битном формате Unix, поэтому результат согласно п.2. Почему примерно 01.01.0001? Потому что, хоть в DateReal 0-вая дата заявлена 01.01.0001, но установка год-месяц-день равными 1 (01.01.0001) даёт в результате DateReal=1.0 - то-есть, прошел один день от какой-то даты. Может быть и ошибка в работе функции SystemTime2DateTime. Выходом может быть уменьшение на 1 номера дня при HeapIntToDateReal. Обсуждение - ниже.

Предлагается следующее:

4) Для функции StrFmtToDateVCL и StrFmtToDateUnix: если порция даты равна 0, установить для результата порцию даты равную 0-вой для данного типа. Для DateReal ничего не поменяется, для VCL/Unix результат будет соответствовать ожидаемому - если мы форматируем только время, то в результате будет правильное время от 0-вой даты.
5) Предлагается для функции XXXToStrFmt, если порция даты меньше 01.01.1601, установить для этой даты минимально допустимое значение 01.01.1601, чтобы иметь возможность хотя бы отобразить время. Было бы хорошо написать свою функцию форматирования, лишенную этого недостатка (вместо системной).
6) В модификации предлагаю дату Unix выдавать в типе data_real вместо data_int. Это позволит расширить диапазон дат этого типа. Если бы захотелось и дальше обрабатывать/выдавать DateUnix в Integer, то нужно в некоторые функции добавить контроль переполнения и либо выдавать ошибку (добавить событие onError), либо подставлять минимальное/максимальное значение при переполнении минимальной/максимальной даты Unix.
7) Функции HeapIntToXXX поправлены: при 0 году, месяце, дне для каждого типа даты устанавливается год-месяц-день 0-вой даты. В общем случае 0 в этих местах не имеют смысла, поэтому им дан новый смысл - "старшие разряды" результата тоже равны 0. В примере если я хочу сконвертировать 2 мин 30 сек в DateUnix, я ожидаю получить в результат 2*60+30 сек = 150. Для остальных типов дат если порция даты 0-вая, то точно так же выдаётся только время.

Немного может быть необычным результат для HeapIntToDateVCL.

При 0 году, месяце, дне результирующая дата равна 30.12.1899 + время.
Если поставить день равным 1, то результат получается по правилам:
- год=0, поэтому подставить 1899
- месяц=0, подставить 12.
- день=1.
Результат: 01.12.1899 + время.
Если к этому ещё поставить и месяц равным 1, то результат: 01.01.1899

Необычность результата в том, что при переходе месяца-дня от 0 к 1, результирующая дата уменьшается, а не остаётся неизменной. Тогда как в HeapIntToDateReal/HeapIntToDateUnix , при дне и месяце равном 0 или 1 результат будет одинаков - 01.01.0001/01.01.1970. Просто потому что месяц/день в "0-вой" дате VCL равен 12/30, а в остальных - 1/1.


Также добавлены точки:
-OffsetUTC - смещение локального времени относительно UTC согласно настроек часового пояса (Real/VCL)
-OffsetUTCUnix - смещение локального времени относительно UTC согласно настроек часового пояса (Unix)

================================

Непонятно, зачем в коде используется проверка
if DateTime > 202751589 then exit;



================================

По поводу HeapIntToDateReal


На крайней справа картинке опечатка в нижней Label: написано "HeapIntToVCL:", а имелось в виду "HeapIntToUnix:"

На скриншоте представлена иллюстрация проблемы. При конвертировании 0-вой даты из HeapInt в результате мы должны получить 0-вую дату (в числовом виде) для данного формата.
То-есть, если ввести в год-месяц-день (остальное - 0):
-для HeapIntToDateReal 1-1-1 - должны получить 0 в DateReal
-для HeapIntToDateVCL 1899-12-30 - должны получить 0 в DateVCL
-для HeapIntToDateUnix 1970-1-1 - должны получить 0 в DateUnix

Но, для HeapIntToDateReal мы получаем дату 1.0 в DateReal, что, по-моему, есть неправильно. Конвертация этой даты в остальные форматы путём добавления соответствующих констант разницы показывает, что результат не равен 0-ым датам соответствующего формата - как раз на один день.

На скриншоте цифрой 1 отмечена невозможность форматирования даты меньше 01.01.1601.
Во всём остальном модифицированный DateConvertor не отличается от оригинального.
Цифра 2 показывает, что после HeapIntToDateReal результирующая DateReal=1 + время. При вычислении из неё других типов, результат получается смещённым на 1 день от 0-вых дат.
Цифра 3 показывает отсутствие такой проблемы при HeapIntTo в остальные форматы - если указана 0-вая дата для этого формата, то и в результате получается 0 в порции даты + время. И при приведении к Real0 и добавлении констант смещения к Real тоже получается 0-вые даты соответствующих форматов.

Вопрос - нужно ли при HeapIntToDateReal уменьшать день на 1, и перед DateRealToHeapInt увеличивать?
В моём моде это включается директивой HEAP_INT_FIX (в архиве - отключена).
карма: 26

1
Голосовали:Joiner
Редактировалось 6 раз(а), последний 2018-09-21 16:31:15