Convert Date/Time (as Double) to struct* tm in C++
I get a date/time as double value from C# (DateTime.ToOADate(), which 开发者_C百科is a OLE Date Time). It contains the passed days from 1899/12/31, with the fraction being the passed part of the day. Multiplied with 86400 I get the seconds and from that finally the day's time.
Getting the date however is harder. I still don't have an solution except for the dates that the UNIX time covers (1970/01/01 to 2038/01/19). During this time, mktime() can be used to convert the passed days to a datetime.
double OleDateTimeValue = 28170.654351851852; // 14.02.1977 15:42:16
struct tm * timeinfo;
int passedDays = (int)OLEDateTimeValue;
// between 1.1.1970 and 18.1.2038
if((passedDays >= 25569) && (passedDays <= 50423))
{
timeinfo->tm_year = 70; //1970
timeinfo->tm_mon = 0;
timeinfo->tm_mday = 1 + (passedDays - 25569);
mktime(timeinfo);
}
else // date outside the UNIX date/time
{
}
Now, mktime() formats the tm struct so that it represents the requested date, or returns -1 if the value is outside the given dates.
Is there a generic way to do the calculation? Unfortunately I can't use MFC and have to use Visual C++ 6.0.
Thanks, Markus
I believe you can use the VariantTimeToSystemTime function to convert into a SYSTEMTIME.
I love date conversions - they make such a nice puzzle!
Here's some code that works for the dates from 1900-03-01 to 2100-02-28. The reason it doesn't work past those boundaries is that 1900 and 2100 are not leap years. This has been tested against Microsoft's COleDateTime and matches every day within the range.
int leapDays = (int)((OleDateTimeValue + 1400) / 1461);
timeinfo->tm_year = (int)((OleDateTimeValue - leapDays - 1) / 365);
int janFirst = timeinfo->tm_year * 365 + (int)((timeinfo->tm_year + 7) / 4);
int wholeDays = (int)OleDateTimeValue - janFirst;
if (timeinfo->tm_year % 4 != 0 && wholeDays > 58)
++wholeDays;
static int firstOfMonth[12] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
timeinfo->tm_mon = std::upper_bound(&firstOfMonth[0], &firstOfMonth[12], wholeDays) - &firstOfMonth[0];
timeinfo->tm_mday = wholeDays - firstOfMonth[timeinfo->tm_mon - 1] + 1;
Conversion of the time portion is trivial, and I leave it as an exercise to the reader.
Converting to time_t should be easy (multiply by 86400 and add a constant offset), then you can use the localtime
function. But you'll still be limited to the range of UNIX time. If you really need beyond that range then villintehaspam's answer, along with copying all the individual fields, looks like the way to go.
精彩评论