将带有时区的纪元时间转换为Excel格式的时间?

Converting Epoch time with timezone to Excel format time?

本文关键字:时间 Excel 格式 转换 纪元 时区      更新时间:2023-10-16

我需要能够将大纪元时间转换为Excel时间。 为什么选择 Excel,因为使用数字 Excel 的时间比在显示格式上完成的任何分析都快。

使用 UTC 15284800192018-06-08 12:46:58 CDT的当前时间应给出0.5326157。 但换算成New_York时间或2018-06-08 13:46:58 EDT会得到0.574282367。 我只需要将时间字段转换为Excel样式。

这是我不完整的代码:

double GetTime(Datetime currtime, std::string tz = "TZ=America/New_York")
{
std::time_t t = currtime;
//tzset(tz);
std::tm tm = *std::localtime(&t);
return ((tm.tm_hour * 3600 + (tm.tm_min) * 60.0 + tm.tm_sec) / 86400.0);
}

该代码有效,但仅适用于"美国/芝加哥"的当地时间。 我一直无法使用将时区设置为我可能需要的时区。 此外,tm 似乎仅限于秒,但我也需要处理毫秒和微秒。

此外,我需要它很快,当前的实现将时间解析为单独的字段,然后将其组合到我需要的内容中,这似乎做了很多额外的工作。

这个问题可以通过Howard Hinnant的免费开源日期/时间/时区库轻松解决,该库非常有效。 该库也在当前的 C++20 工作草案中,在namespace std::chrono下。 因此,将来将代码移植到仅使用 std::lib 应该像更改几个命名空间一样简单。

double
GetTime(std::chrono::system_clock::time_point currtime,
date::time_zone const* tz = date::current_zone())
{
using namespace date;
using namespace std::chrono;
zoned_time<system_clock::duration> zt{tz, currtime};
auto lt = zt.get_local_time();
auto ld = floor<days>(lt);
using ExcelTime = duration<double, days::period>;
ExcelTime tod = lt - ld;
return tod.count();
}

它不需要Datetime,而是需要std::chrono::system_clock::time_point,而不是std::string,而是date::time_zone const*

在三大平台(llvm/gcc/MSVS(上,最粗略system_clock::time_point是微秒,这符合您的精度目标。

第一步是创建一个zoned_time,它是time_pointtime_zone的配对。 从这个可以得到一个local_time.

floor<days>截断time_point的精度以days。 如果从更精细的精度time_point中减去日精度time_point,则得到当地时间。

如果将此本地时间存储在以double表示形式和 1 天的时间段的chrono::duration中,则获得 Excel 时间格式。

这可以像这样使用:

int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << std::fixed << std::setprecision(9);
std::cout << GetTime(sys_seconds{1528480019s}, locate_zone("America/Chicago")) << 'n';
zoned_time<system_clock::duration> zt{"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s};
std::cout << GetTime(zt.get_sys_time(), zt.get_time_zone()) << 'n';
}

其中输出:

0.532627315
0.574282407

上面,我努力尽可能接近您现有的 API。 但是,如果您采用此库,则可以通过采用"更原生"的 API 使其更简单、更高效:

std::chrono::duration<double, date::days::period>
GetTime(const date::zoned_time<std::chrono::system_clock::duration>& zt)
{
using namespace date;
auto lt = zt.get_local_time();
return lt - floor<days>(lt);
}

现在GetTime只接受一个类型为zoned_time<system_clock::duration>的参数,并返回一个duration<double, days::period>。 剩下GetTime要做的就是将本地时间截断为天精度,然后减去以获得一天中的时间。

main中的演示也得到了简化:

std::cout << GetTime({"America/Chicago", sys_seconds{1528480019s}}).count() << 'n';
std::cout << GetTime({"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s}).count() << 'n';

并提供与以前相同的输出。