Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Правильный алгоритм конвертации даты и времени из TDateTime в Unix-эпоху для C++

Delphi , Синтаксис , Дата и Время

Вопрос о конвертации времени из формата TDateTime, используемого в Delphi, в Unix-эпоху является актуальным для разработчиков, работающих с несколькими языками программирования. В Delphi, TDateTime представлен как двойное число, где целочисленная часть указывает количество дней, прошедших с 30 декабря 1899 года, а дробная часть - время суток в миллисекундах.

Проблема

Необходимо корректно конвертировать значение TDateTime в Unix-эпоху. Существующий код для конвертации приводит к неверным результатам, например, для значения TDateTime 37838.001388888886 (5 августа 2003 года, 02:00) код возвращает Unix-время 1060041719, что соответствует 5 августа 2003 года, 00:01:59, что явно неверно.

Решение

В компонентах RTL Delphi/C++Builder есть функция DateTimeToUnix(), предназначенная именно для такой конвертации. Важно понимать, что TDateTime имеет точность до миллисекунд, и для корректной конвертации необходимо учитывать это. В современных версиях RTL используется алгоритм, который избегает потери точности, связанной с плавающей точкой, и вместо этого использует TTimeStamp.

Алгоритм конвертации

Для конвертации TDateTime в Unix-время можно использовать следующий алгоритм, адаптированный для C++:

#include <cmath>
#include <cstdint>

#define HoursPerDay   24
#define MinsPerHour   60
#define SecsPerMin    60
#define MSecsPerSec   1000
#define MinsPerDay    (HoursPerDay * MinsPerHour)
#define SecsPerDay    (MinsPerDay * SecsPerMin)
#define SecsPerHour   (SecsPerMin * MinsPerHour)
#define MSecsPerDay   (SecsPerDay * MSecsPerSec)

#define UnixDateDelta 25569 // Количество дней между базой TDateTime (30.12.1899) и Unix time_t (1.1.1970)
#define DateDelta 693594    // Количество дней между 1.1.0001 и 30.12.1899

const float FMSecsPerDay = MSecsPerDay;
const int IMSecsPerDay = MSecsPerDay;

struct TTimeStamp
{
    int Time; // Количество миллисекунд с начала суток
    int Date; // Количество дней, прошедших с 1.1.0001
};

typedef double TDateTime;

TTimeStamp DateTimeToTimeStamp(TDateTime DateTime)
{
    __int64 LTemp = std::round(DateTime * FMSecsPerDay);
    __int64 LTemp2 = LTemp / IMSecsPerDay;
    TTimeStamp Result;
    Result.Date = DateDelta + LTemp2;
    Result.Time = std::abs(LTemp) % IMSecsPerDay;
    return Result;
}

__int64 DateTimeToMilliseconds(const TDateTime ADateTime)
{
    TTimeStamp LTimeStamp = DateTimeToTimeStamp(ADateTime);
    return (__int64(LTimeStamp.Date) * MSecsPerDay) + LTimeStamp.Time;
}

__int64 SecondsBetween(const TDateTime ANow, const TDateTime AThen)
{
    return std::abs(DateTimeToMilliseconds(ANow) - DateTimeToMilliseconds(AThen)) / MSecsPerSec;
}

__int64 DateTimeToUnix(const TDateTime AValue)
{
    __int64 Result = SecondsBetween(UnixDateDelta, AValue);
    if (AValue < UnixDateDelta)
        Result = -Result;
    return Result;
}

Альтернативный способ

Использование библиотеки Howard Hinnant для C++20, которая предоставляет удобные средства для работы с датой и временем:

#include "date/date.h"
#include <iostream>

date::sys_seconds convert(double d)
{
    using namespace date;
    using namespace std::chrono;
    using ddays = duration<double, days::period>;

    return round<seconds>(sys_days{1899_y/12/30} + ddays{d});
}

int main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    auto tp = convert(37838.001388888886);
    cout << tp << " = " << (tp-sys_seconds{})/1s << '\n';
}

Вывод программы будет следующим:

2003-08-05 00:02:00 = 1060041720

Обратите внимание, что для использования данной библиотеки необходимо добавить определение NOMINMAX перед подключением заголовочных файлов, чтобы избежать конфликтов с макросами, определенными в Windows.h.

Используя предложенные алгоритмы, можно корректно конвертировать значения TDateTime в Unix-время для дальнейшего использования в C++ коде.

Создано по материалам из источника по ссылке.

Описание алгоритма конвертации даты и времени из формата `TDateTime`, используемого в Delphi, в Unix-эпоху для программирования на C++.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: Дата и Время ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-02-05 14:46:31/0.0056400299072266/1