C++ UnixTimestamp 和可读的时间格式

Posted

技术标签:

【中文标题】C++ UnixTimestamp 和可读的时间格式【英文标题】:C++ UnixTimestamp and readable time format 【发布时间】:2018-02-20 14:00:18 【问题描述】:

我从我的 C++ 应用程序中的数据库中获取时间戳作为 AnsiString。 它看起来像这样“2017-09-12 09:35:10”。

现在我想将其解析回 Unix 时间戳。

AnsiString myDate = Query->Fields->FieldByName("MyDates")->AsString;
TDateTime = StrToDateTime(myDate);

在我的具体情况下,我得到以下日期:2017-08-10 08:43:35

但我得到的 Unix 时间戳是:42957.363599537

这是 01-01-1970 12:55:57 计算回可读格式。

我在这里错过了什么?!...

【问题讨论】:

这看起来像是某种扩展的 C++(AsString 是成员 变量 还是某种“属性”函数?)而且 Unix 时间戳不是浮点值,但是整数,所以你拥有的是不同的东西。 @Someprogrammerdude 如果FieldByName 返回一个指向结构的指针,那么->AsString 可能是一个成员变量...但我同意,这不会是预期的 ,但可能 @druckermanly 考虑到我怀疑它是 Embarcadero C++ 构建器的类型,它可能为该语言添加了一些扩展。以及没有“正确”的 Unix 时间戳。 你为什么认为TDateTime是一个unix时间戳? 应用程序是用 Borland C++ 5 构建的。 【参考方案1】:

不是 Unix TimeStamp,而是TDateTime。以下来自 Builder 的文档:

TDateTime 值的组成部分是拥有的天数 自 1899 年 12 月 30 日通过。 TDateTime 值的小数部分是 一天中的时间。

在其他情况下,Unix TimeStump 是从 01.01.1970 开始的秒数

【讨论】:

【参考方案2】:

您可以尝试 Howard Hinnant's free, open source, header-only, date/time library,它扩展了 C++11 的 <chrono> 标头来处理日历计算。

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

int
main()

    std::istringstream in"2017-08-10 08:43:35";
    date::sys_seconds Unixtimestamp;
    in >> date::parse("%F %T", Unixtimestamp);
    std::cout << Unixtimestamp.time_since_epoch().count() << '\n';
    std::cout << date::format("%F %T\n", Unixtimestamp);

输出:

1502354615
2017-08-10 08:43:35

【讨论】:

不错,但 OP 使用的是不支持 C++11 的旧版 C++Builder。 太糟糕了。我很幸运能够使用现代 C++ 工作。【参考方案3】:

C++Builder 6 及更高版本在DateUtils 单元中有一个DateTimeToUnix() 函数:

#include <SysUtils.hpp>
#include <DateUtils.hpp>

AnsiString myDateStr = Query->Fields->FieldByName("MyDates")->AsString;
TDateTime myDate = StrToDateTime(myDateStr);
__int64 myTimestamp = DateTimeToUnix(myDate);

如果您使用的是 C++Builder 5 或更早版本,您可以像这样实现自己的 DateTimeToUnix() 函数:

#include <SysUtils.hpp>

// Days between TDateTime basis (12/31/1899) and Unix time_t basis (1/1/1970)
const __int64 UnixDateDelta = 25569;

__int64 DateTimeToMilliseconds(const TDateTime &ADateTime)

    TTimeStamp LTimeStamp = DateTimeToTimeStamp(ADateTime);
    return (__int64(LTimeStamp.Date) * MSecsPerDay) + LTimeStamp.Time;


__int64 DateTimeToUnix(const TDateTime &AValue)

    __int64 Result = abs(DateTimeToMilliseconds(UnixDateDelta) - DateTimeToMilliseconds(AValue)) / MSecsPerSec;
    if (AValue < UnixDateDelta)
        Result = -Result;
    return Result;

另请注意,您使用的StrToDateTime() 版本取决于用户当前的日期/时间区域设置。由于您正在处理非常具体的日期/时间格式,我建议您手动解析它,而不是依赖任何特定的语言环境,例如:

#include <SysUtils.hpp>
#include <stdio.h>

AnsiString myDateStr = Query->Fields->FieldByName("MyDates")->AsString;

Word wYear, wMonth, wDay, wHour, wMin, wSec;
sscanf(myDateStr.c_str(), "%hu-%hu-%hu %hu:%hu:%hu", &wYear, &wMonth, &wDay, &wHour, &wMin, &wSec);

TDateTime myDate = EncodeDate(wYear, wMonth, wDay) + EncodeTime(wHour, wMin, wSec, 0);
__int64 myTimestamp = DateTimeToUnix(myDate);

如果您使用的是 C++Builder 2006 或更高版本,则可以使用接受 TFormatSettings 结构作为输入的 StrToDateTime() 的重载版本:

#include <SysUtils.hpp>
#include <DateUtils.hpp>

String myDateStr = Query->Fields->FieldByName("MyDates")->AsString;

TFormatSettings myFmt = TFormatSettings::Create();
myFmt.ShortDateFormat = _D("yyyy-mm-dd hh:nn:ss");
myFmt.DateSeparator = _D('-');
myFmt.TimeSeparator = _D(':');

TDateTime myDate = StrToDateTime(myDateStr, myFmt);
__int64 myTimestamp = DateTimeToUnix(myDate);

【讨论】:

以上是关于C++ UnixTimestamp 和可读的时间格式的主要内容,如果未能解决你的问题,请参考以下文章

C++ IP 地址人类可读的形式

编译 C++ 源代码以将 .off 文件转换为 Android OpenGL ES 可读的 XML 的问题

如何使用 perf 收集一些可读的堆栈跟踪?

Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的特点

nodejs的流总结

如何将纳秒的纪元时间转换为人类可读的?