I have already found several answers related to converting a std::time_t value to System::DateTime and back. However, almost all answers seem to neglect that the type of std::time_t is actually undefined in the standard. Most solutions just cast std::time_t to whatever needed or apply arithmetic operations to a std::time_t object which is possible since it's an arithmetic type, but there is no specification about the result of such an operation. I know that most compilers define time_t as an int of some size but the fact alone that it has changed from int32 to int64 in many implementations recently shows that changes are indeed possible.
So I've come up with this solution which should work with any type of std::time_t. It works from what I have seen. But I was wondering - Are there any possible pitfalls I might be unaware of?
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 assumptions were made:
- Resulting
std::time_tshould be in UTC since it doesn't contain any info on localization - Resulting
System::DateTimeshould be local time sinceSystem::DateTime::Nowreturns a localizedDateTime makeUtcTimeis a helper function creating astd::tmfrom the values supplied and creates a UTCstd::time_tout of it. This is currently implemented using_mkgmtimebecause our interop code can safely rely on the existence of Microsoft extensions. However, a UTC version ofmktimeis readily available in other compilers as well (standardmktimeexpects local time).
2 less important things to consider:
- The
const_castis necessary because the marshal_as-template expects aconst T&as parameter and I can't access the properties of a const .NET value-type object. However there might be a better solution. - Should the
unix_epoch...stuff bestatic const?
(I wasn't sure if this should be posted on "Programmers Exchange" since it's more of a discussion but since it's a very specific C++ question I thought SO might be the better place to ask)