我已经找到了几个与将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
,并从中创建一个UTC std::time_t
。目前这是使用_mkgmtime
实现的,因为我们的互操作代码可以安全地依赖于Microsoft扩展的存在。但是,mktime
的UTC版本也可以在其他编译器中使用(标准mktime
需要本地时间)。 要考虑的两件不太重要的事情:
const_cast
是必需的,因为marshal_as-template需要const T&
作为参数,我无法访问const .NET值类型对象的属性。但是,可能有更好的解决方案。 unix_epoch...
内容应该是static const
吗?(我不确定这是否应该发布在“程序员交换”上,因为它更多的是讨论,但由于这是一个非常具体的C ++问题,我认为可能是更好的地方提问)
答案 0 :(得分:12)
坚持采用“符合标准”的方式进行转换并不是很有效率。 Ecma-372 standard涵盖了std :: time_t和System :: DateTime将会遇到的唯一地方。其中现在只有一个实现。可以假设Mono项目是另一个项目的最可能来源,但是现在他们似乎对提供混合模式实现完全不感兴趣,这是您考虑使用C ++ / CLI的唯一原因。
std :: time_t正在稳步迈向Y2K38灾难。微软先发制人地做了一些事情,并且因为他们选择LLP64而真的不得不这样做,但是其他人都指望他们LP64 data model让他们摆脱困境。换句话说,2038年仍然没有剩余的32位处理器。这很可能是一个自我实现的预言。
无论如何,转换必须与1970年1月1日以来经过的秒数一起工作。这可以是32位或64位整数值,具体取决于实现。我可以给予的唯一保证是这段代码至少在2038年之前是好的:
#include <ctime>
using namespace System;
public ref class Conversions {
public:
static DateTime time_t2DateTime(std::time_t date) {
double sec = static_cast<double>(date);
return DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind::Utc).AddSeconds(sec);
}
static std::time_t DateTime2time_t(DateTime date) {
TimeSpan diff = date.ToUniversalTime() - DateTime(1970, 1, 1);
return static_cast<std::time_t>(diff.TotalSeconds);
}
};
答案 1 :(得分:0)
以下是我的团队到达的解决方案:
DateTime表示自1899年12月30日午夜以来的混合分数天数,表示为双倍。我相信这个纪元日期用于说明1900年不闰年这一事实,并且它允许额外的两天(为什么两个而不是一个? - 我不清楚为什么不选择1899年12月31日作为他们的时代。)
因此,日期时间2.50将相当于1900年1月1日12:00:00(即该部分代表当天的1/2 - 下午12点)。
我们计算出1970年1月1日--Unix Epoch--是DateTime Epoch之后的25569天。
所以等效公式为:
#include <time.h>
System::DateTime toDateTime(time_t &t)
{
return 25569.0 + t / 86400.0; // ensure you use floating point math or you will truncate the fractional portion
}