如何在 C++ 中将 Pascal TDateTime(double) 时间转换为 Unix 纪元

2023-12-03

我需要使用 C++ 将双精度值 Pascal TDateTime 对象转换为 Unix 纪元。

提出了一个可能的解决方案():

unsigned int UnixStartDate = 25569;

unsigned int DateTimeToUnix(double ConvDate)
{
  return((unsigned int)((ConvDate - UnixStartDate) * 86400.0));
}

但是,此转换代码会产生如下错误:

TDateTime 时间值 = 37838.001388888886 (05.08.2003 02:00)

它转换为 Unix 纪元 1060041719 (05.08.2003 00:01:59),这显然是不正确的。

如何准确转换这个 TDateTime 值?


Delphi/C++Builder RTL 有一个DateTimeToUnix()函数就是为了这个目的。

In a TDateTime,整数部分是从December 30 1899,小数部分是一天中的时间00:00:00.000。使用涉及不止一整天的原始数学可能有点棘手,因为浮点数学不准确.

例如,0.001388888886不完全是00:02:00,它更接近于00:01:59.999。所以你遇到了舍入问题,这正是你必须注意的。TDateTime具有毫秒精度,并且有86400000一天中有几毫秒,所以.001388888886 is 119999.9997504过去几毫秒00:00:00.000,即00:01:59如果这些毫秒被截断为119999, or 00:02:00如果它们被四舍五入到120000.

RTL 停止使用浮点运算TDateTime几年前由于微妙的精度损失。现代的TDateTime操作通过进行往返TTimeStamp现在要避免这种情况。

由于您尝试从 RTL 外部执行此操作,因此您需要在代码中实现相关算法。您所展示的算法是 RTL 如何used转换一个TDateTime到许多年前的 Unix 时间戳,但现在不再这样做了。当前的算法现在看起来更像这样(从原始 Pascal 转换为 C++):

#include <cmath>

#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 // Days between TDateTime basis (12/31/1899) and Unix time_t basis (1/1/1970)
#define DateDelta 693594    // Days between 1/1/0001 and 12/31/1899

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

struct TTimeStamp
{
    int Time; // Number of milliseconds since midnight
    int Date; // One plus number of days since 1/1/0001
};

typedef double TDateTime;

TTimeStamp DateTimeToTimeStamp(TDateTime DateTime)
{
    __int64 LTemp = std::round(DateTime * FMSecsPerDay); // <-- this might require tweaking!
    __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;
}

请注意我的评论DateTimeToTimeStamp()。我不确定是否std::round()产生exactly与德尔福的结果相同System::Round()对于所有值。你必须尝试一下。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 C++ 中将 Pascal TDateTime(double) 时间转换为 Unix 纪元 的相关文章

  • 如何验证文件名称在 Windows 中是否有效?

    是否有一个 Windows API 函数可以将字符串值传递给该函数 该函数将返回一个指示文件名是否有效的值 我需要验证文件名是否有效 并且我正在寻找一种简单的方法来完成此操作 而无需重新发明轮子 我正在直接使用 C 但针对的是 Win32
  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • 获取按下的按钮的返回值

    我有一个在特定事件中弹出的表单 它从数组中提取按钮并将标签值设置为特定值 因此 如果您要按下或单击此按钮 该函数应返回标签值 我怎样才能做到这一点 我如何知道点击了哪个按钮 此时代码返回 DialogResult 但我想从函数返回 Tag
  • 为什么 Delphi 中的 ADO Next 记录处理速度变慢?

    我有一个多年前开发的 Delphi 4 程序 它使用Opus 直接访问 http sourceforge net projects directaccess 按顺序搜索 Microsoft Access 数据库并检索所需的记录 Delphi
  • 如何忽略“有符号和无符号整数表达式之间的比较”?

    谁能告诉我必须使用哪个标志才能使 gcc 忽略 有符号和无符号整数表达式之间的比较 警告消息 gcc Wno sign compare 但你确实应该修复它警告你的比较
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • C#:如何防止主窗体过早显示

    在我的 main 方法中 我像往常一样启动主窗体 Application EnableVisualStyles Application SetCompatibleTextRenderingDefault false Application
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • 在 ASP.NET Core 3.1 中使用包含“System.Web.HttpContext”的旧项目

    我们有一些用 Net Framework编写的遗留项目 应该由由ASP NET Core3 1编写的API项目使用 问题是这些遗留项目正在使用 System Web HttpContext 您知道它不再存在于 net core 中 现在我们
  • C# 中的递归自定义配置

    我正在尝试创建一个遵循以下递归结构的自定义配置部分
  • Github Action 在运行可执行文件时卡住

    我正在尝试设置运行google tests on a C repository using Github Actions正在运行的Windows Latest 构建过程完成 但是当运行测试时 它被卡住并且不执行从生成的可执行文件Visual
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • 在 Dynamics CRM 插件中访问电子邮件发件人地址

    我正在编写一个 Dynamics CRM 2011 插件 该插件挂钩到电子邮件实体的更新后事件 阶段 40 pipeline http msdn microsoft com en us library gg327941 aspx 并且在此阶
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐