В программе VCL Delphi (11.3) я использую метод для преобразования тиков 638563016295520210
в TDateTime
. Я знаю, что Delphi работает с TDateTime
из 12/30/1899
, и я пробовал использовать TTimeSpan.FromTicks()
, но безуспешно.
Вот функция, которую я вызываю:
function TicksToDateTime(Ticks: Int64): TDateTime; // Ticks input is 638563016295520210
const
TicksPerDay = 864000000000; // Number of ticks in a day
var
Days, RemainingTicks, FractionOfDay: Int64;
BaseDate: TDateTime;
begin
BaseDate := EncodeDate(1, 1, 1); // January 1, 0001
Days := Ticks div TicksPerDay; // Calculate the number of days (638563016295520210 div 864000000000)
RemainingTicks := Ticks mod TicksPerDay; // Calculate the Remaining Ticks
FractionOfDay := RemainingTicks div TicksPerDay; // Convert Remaining Ticks to Fraction of a Day
Result := BaseDate + Days + (RemainingTicks div TicksPerDay); // The Result should equal 07/11/2024 9:33 AM EST.
end;
Я звоню через:
MyDate := TicksToDateTime(iTicks);
А затем форматируем результат TDateTime
. Вызов функции дает мне результат даты 05/10/0203
. Как мне получить желаемый результат 07/11/2024 9:33 AM
?
@AmigoJack — Тики, о которых я говорю, — это тики UTC, представляющие количество 100-наносекундных интервалов, прошедших с полуночи 1 января 0001 года по (UTC). Когда я ввожу количество тиков в datetimetotics-converter, он конвертируется правильно.
Невозможно воспроизвести: помещение «63856301629552021» в правое текстовое поле преобразует левое текстовое поле в «10/05/0203 18:09:50». Также обратите внимание, что формат даты — «дд/ММ/гггг», а не (как вы подразумеваете) «ММ/дд/гггг». Пожалуйста, отредактируйте свой вопрос о том, что вы на самом деле сделали (включая ошибочный код и ссылки на веб-сайты), чего вы ожидали и что произошло вместо этого. Для пояснения формат даты ISO максимально однозначен (это позволяет избежать путаницы британского и американского форматов).
TDateTime
реализуется с использованием значения с плавающей запятой Double
, где дата находится в целой части, а время — в дробной части.
div
выполняет целочисленное деление, из него нельзя получить дробь. Вместо этого вам нужно использовать /
, который выполняет деление с плавающей запятой.
Но, в любом случае... в комментариях вы сказали:
Когда я ввожу количество тиков в datetimetotics-converter, он конвертируется правильно
Это не то, что я вижу. Когда я ввожу ваше входное значение 63856301629552021
на этот сайт, он сообщает 10/05/0203 18:09:22
(10 мая 02:03, 18:09:22), а не 07/11/2024 09:33:00
(11 июля?, 7 ноября? 2024, 9:33 утра), как вы ожидаете.
В этом есть смысл, как прокомментировал @AmigoJack:
63856301629552021 div 864000000000 = 73907 дней = 202 года... Ожидается, что добавление 202 лет и чего-то к 0001-01-01 в сумме даст 0203-01-01 и что-то в этом роде.
(конечно, его комментарий не учитывает месяцы и дни каждого месяца, но суть вы поняли.)
Итак, либо ваши данные неверны, либо ваши ожидания неверны (вероятно, и то, и другое).
По данным этого сайта:
11 июля 2024 г., 9:33 = 638562871800000000
07 ноя 2024 9:33 = 638665687800000000
Обратите внимание, что ваше входное значение составляет 17 цифр, но оба значения выше — 18 цифр, что означает, что вашим входным данным не хватает достаточной точности, чтобы достичь где-то близкого к 2024 году.
Когда я использую следующий код и правильные входные значения, я получаю ожидаемое значение TDateTime
:
uses
System.DateUtils, System.TimeSpan;
function TicksToDateTime(Ticks: Int64): TDateTime;
begin
Result := IncMillisecond(
EncodeDate(1, 1, 1),
Trunc(TTimeSpan.FromTicks(Ticks).TotalMilliseconds)
);
end;
TicksToDateTime(63856301629552021 ) // returns May 10 0203 6:09:22.955 PM
TicksToDateTime(638562871800000000) // returns Jul 11 2024 9:33:00.000 AM
TicksToDateTime(638665687800000000) // returns Nov 07 2024 9:33:00.000 AM
Если вы не хотите использовать TTimeSpan
, небольшая настройка существующего кода даст аналогичные1 результаты:
function MyTicksToDateTime(Ticks: Int64): TDateTime;
const
TicksPerDay = 864000000000;
var
BaseDate: TDateTime;
Days: Int64;
RemainingTicks: Int64;
FractionOfDay: Double; // <--
begin
BaseDate := EncodeDate(1, 1, 1);
Days := Ticks div TicksPerDay;
RemainingTicks := Ticks mod TicksPerDay;
FractionOfDay := RemainingTicks / TicksPerDay; // <--
Result := BaseDate + Days + FractionOfDay;
end;
TicksToDateTime(63856301629552021 ) // returns May 11 0203 5:50:37.045 AM
TicksToDateTime(638562871800000000) // returns Jul 11 2024 9:33:00.000 AM
TicksToDateTime(638665687800000000) // returns Nov 07 2024 9:33:00.000 AM
1: обратите внимание, что в этом случае 63856301629552021
возвращает May 11 0203 5:50:37.045 AM
вместо May 10 0203 6:09:22.955 PM
, как в случае с TTimeSpan
. Я не уверен, почему такая разница, и мне не хочется разбираться в этом прямо сейчас. Это как-то связано с тем, как FractionOfDay
(неправильно?) рассчитывается. Однако два других значения возвращают правильный результат.
63856301629552021 дел 864000000000 = 73907 дней = 202 года. Разделив остаток 73907 дней еще раз на день (
(RemainingTicks div TicksPerDay)
), всегда будет получено0
(потому что оно всегда меньше 864000000000). Ожидается, что добавление 202 лет и чего-то к 0001-01-01 в сумме даст 0203-01-01 и что-то в этом роде. Какое определение слова «клещи» вы имели в виду? Они действительно считаются с 01.01.01? Та же точность используется TFileTime, но она начинается с 01.01.1601. «Промежуток времени» не является датой.