【发布时间】:2014-02-11 11:32:41
【问题描述】:
我已经找到了几个与将 std::time_t 值转换为 System::DateTime 并返回相关的答案。但是,几乎所有答案似乎都忽略了 std::time_t 的类型实际上在标准中是未定义的。大多数解决方案只是将std::time_t 转换为任何需要的对象,或者将算术运算应用于std::time_t 对象,这是可能的,因为它是一种算术类型,但没有关于此类操作结果的规范。我知道大多数编译器将time_t 定义为一定大小的int,但仅在最近的许多实现中它已从int32 更改为int64 的事实表明,更改确实是可能的.
所以我想出了这个应该适用于任何类型的std::time_t 的解决方案。它从我所看到的工作。但我想知道 - 有没有我可能没有意识到的陷阱?
template <>
inline System::DateTime marshal_as(const std::time_t &from_object)
{
// Returns DateTime in Local time format from time_t (assumed to be UTC)
const auto unix_epoch = makeUtcTime(1970, 1, 1, 0, 0, 0);
const auto unix_epoch_dt = System::DateTime(1970, 1, 1, 0, 0, 0, System::DateTimeKind::Utc);
const auto secondsSinceEpoch = std::difftime(from_object, unix_epoch);
return const_cast<System::DateTime&>(unix_epoch_dt).AddSeconds(secondsSinceEpoch).ToLocalTime();
} // end of System::DateTime marshal_as(const std::time_t &from_object)
template <>
inline std::time_t marshal_as(const System::DateTime &from_object)
{
// Returns time_t in UTC format from DateTime
auto from_dt = const_cast<System::DateTime&>(from_object).ToUniversalTime();
return makeUtcTime(from_dt.Year, from_dt.Month, from_dt.Day, from_dt.Hour, from_dt.Minute, from_dt.Second);
} // end of std::time_t marshal_as(const System::DateTime &from_object)
做了3个假设:
- 生成的
std::time_t应该是 UTC,因为它不包含任何本地化信息 - 生成的
System::DateTime应该是本地时间,因为System::DateTime::Now返回一个本地化的DateTime -
makeUtcTime是一个辅助函数,根据提供的值创建std::tm并从中创建 UTCstd::time_t。这目前是使用_mkgmtime实现的,因为我们的互操作代码可以安全地依赖于 Microsoft 扩展的存在。但是,mktime的 UTC 版本在其他编译器中也很容易获得(标准mktime需要本地时间)。
需要考虑的2个不太重要的事情:
-
const_cast是必需的,因为 marshal_as-template 需要const T&作为参数,而我无法访问 const .NET 值类型对象的属性。但是,可能有更好的解决方案。 -
unix_epoch...应该是static const吗?
(我不确定这是否应该发布在“程序员交流”上,因为它更多的是讨论,但由于这是一个非常具体的 C++ 问题,我认为 SO 可能是更好的提问场所)
【问题讨论】:
-
有两种可能的time_t定义,取决于是否定义了_USE_32BIT_TIME_T。如果已定义,它将在 32 位 time_t 工作时工作。 System::DateTime 是 64 位的。
-
确实如此,感谢您提供的信息。但是由于第二个 marshal_as 中生成的 time_t 是使用日历值 (Year, Month, ...) 构造的,因此可能发生的最糟糕的事情是 time_t 返回为 (time_t)(-1),这基本上意味着转换失败,因为选择的 time_t 实现不能代表 DateTime。但是你去了,原因 #1 为什么简单地将 TotalSeconds 转换为 time_t 可能会失败。
标签: .net datetime c++-cli mixed-mode time-t