I'm converting some c++ to c# code. I cannot reproduce equivalent values when converting from the tm
struct and mktime()
to c#.
Example: Both versions use the same values:
int year = 2022;
int month = 9;
int day = 5;
int hour = 0;
int minute = 27;
int second = 20;
In C++:
struct tm sampleTime;
unsigned long longTime;
sampleTime.tm_year = year;
sampleTime.tm_mon = month - 1;
sampleTime.tm_mday = day;
sampleTime.tm_hour = hour;
sampleTime.tm_min = minute;
sampleTime.tm_sec = second;
sampleTime.tm_wday = 0;
sampleTime.tm_yday = 0;
sampleTime.tm_isdst= 0;
longTime = mktime(&thistime);
The value of longTime
is 1662366439
.
In C#:
DateTime sampleTime = new DateTime(year, month, day, hour, minute, second);
DateTime unixEpoch = new DateTime(1970, 1, 1);
ulong longTime = (ulong)(sampleTime - unixEpoch).TotalSeconds;
The value of longTime
is 1662337639
.
So they are very close but off, and I need them to be equivalent. What am I missing here?
mktime()
takes in a tm
expressed in local time, whereas the Unix epoch is expressed in UTC time instead.
The C# DateTime()
constructors you are calling don't know whether the specified date/time values are in local time or UTC time, so the Kind
property of the resulting DateTime
s is Unspecified
, which can cause calculation errors. So, you need to use other DateTime
constructors that make each Kind
explicit so adjustments can be made as needed during calculations, eg:
DateTime sampleTime = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local);
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
That being said, note that the C++ code is setting sampleTime.tm_isdst = 0
to indicate that the specified date/time IS NOT in DST time, even if the real date/time actually IS in DST time.
I'm not sure how to handle that on the C# side. You will probably have to lookup whether the specified sampleTime
is actually in DST (ie, via TimeZoneInfo.Local.IsDaylightSavingTime()
) and if so then adjust it accordingly to move it out of DST before then performing further calculations on it, eg:
DateTime sampleTime = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local);
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
TimeZoneInfo tz = TimeZoneInfo.Local;
if (tz.SupportsDaylightSavingTime && if tz.IsDaylightSavingTime(sampleTime))
{
// figure out the difference between Standard/Daylight times
// for this timezone at the specified date/time and adjust
// sampleTime accordingly ...
}