Преобразование тиков в TDatetime в Delphi

В программе 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?

63856301629552021 дел 864000000000 = 73907 дней = 202 года. Разделив остаток 73907 дней еще раз на день ((RemainingTicks div TicksPerDay)), всегда будет получено 0 (потому что оно всегда меньше 864000000000). Ожидается, что добавление 202 лет и чего-то к 0001-01-01 в сумме даст 0203-01-01 и что-то в этом роде. Какое определение слова «клещи» вы имели в виду? Они действительно считаются с 01.01.01? Та же точность используется TFileTime, но она начинается с 01.01.1601. «Промежуток времени» не является датой.

AmigoJack 10.08.2024 00:36

@AmigoJack — Тики, о которых я говорю, — это тики UTC, представляющие количество 100-наносекундных интервалов, прошедших с полуночи 1 января 0001 года по (UTC). Когда я ввожу количество тиков в datetimetotics-converter, он конвертируется правильно.

Hackbrew 10.08.2024 00:53

Невозможно воспроизвести: помещение «63856301629552021» в правое текстовое поле преобразует левое текстовое поле в «10/05/0203 18:09:50». Также обратите внимание, что формат даты — «дд/ММ/гггг», а не (как вы подразумеваете) «ММ/дд/гггг». Пожалуйста, отредактируйте свой вопрос о том, что вы на самом деле сделали (включая ошибочный код и ссылки на веб-сайты), чего вы ожидали и что произошло вместо этого. Для пояснения формат даты ISO максимально однозначен (это позволяет избежать путаницы британского и американского форматов).

AmigoJack 10.08.2024 01:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 (неправильно?) рассчитывается. Однако два других значения возвращают правильный результат.

Другие вопросы по теме