Reputation: 4845
Below is the method I use that takes in three inputs:
dateTimeInput
which is a string that represents a date.
inputFormat
are my format
strings like this format: yyyy-MM-dd'T'HH:mm:sszzz
.
timeZoneStandardName
are unique timezone identifiers retrieved from var TimeZoneList = TimeZoneInfo.GetSystemTimeZones();
where the ID is retrieved via timeZoneList.Id
.
I mainly used TimeZoneInfo
to get my hours and minute offsets because it's very explicit as to what city/timezone it is, e.g. UTC
is the input string.
public int dateTimeToUnixTime(string dateTimeInput, string inputFormat, string timeZoneStandardName)
{
DateTime result;
CultureInfo provider = CultureInfo.InvariantCulture;
TimeZoneInfo objTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneStandardName);
int timeZoneHours = objTimeZoneInfo.BaseUtcOffset.Hours;
int timeZoneMinutes = objTimeZoneInfo.BaseUtcOffset.Minutes;
// if input format is "yyyy-MM-dd'T'HH:mm:sszzz"
if (inputFormat == "yyyy-MM-dd'T'HH:mm:sszzz")
{
result = DateTime.ParseExact(dateTimeInput, inputFormat, provider, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
int unixTime = (Int32)(result.Subtract(Epoch)).TotalSeconds;
return unixTime;
}
else
{
// if other input formats
result = DateTime.ParseExact(dateTimeInput, inputFormat, provider, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
int unixTime = (Int32)(result.AddHours(-timeZoneHours).AddMinutes(-timeZoneMinutes).Subtract(Epoch)).TotalSeconds;
return unixTime;
}
}
My second method takes in a Unix timestamp and a timezone specifier and outputs as a location-dependent time:
public string unixTimeToDateTime(int unixInput, string outputFormat, string timeZoneStandardName)
{
// output format is "yyyy-MM-dd'T'HH:mm:sszzz"
TimeZoneInfo objTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneStandardName);
int timeZoneHours = objTimeZoneInfo.BaseUtcOffset.Hours;
int timeZoneMinutes = objTimeZoneInfo.BaseUtcOffset.Minutes;
if (outputFormat == "yyyy-MM-dd'T'HH:mm:sszzz")
{
System.DateTime dateTime = Epoch.AddSeconds(unixInput);
return dateTime.AddHours(timeZoneHours).AddMinutes(timeZoneMinutes).ToString("yyyy-MM-dd'T'HH:mm:ss") + toTimeSpan(timeZoneHours, timeZoneMinutes);
}
// output format is not
else
{
System.DateTime dateTime = Epoch.AddSeconds(unixInput).AddHours(timeZoneHours).AddMinutes(timeZoneMinutes);
return dateTime.ToString(outputFormat);
}
}
For example, here is this method in a Grasshopper component for me to show you what I mean. dateTimeToUnixTime()
is my first "clock", while unixTimeToDateTime()
is my second "clock"
Given an input of those list of times and a timezone marker of EST, and given those dates (mind you November 2nd 2014 1-2 AM is when we get our DST adjustments again), this method theoretically should adjust its timezone to offset an hour.
I know that TimeZoneInfo
supports DST because I can use the below method to show a bool
of a respective timezone's DST status.
var TimeZoneList = TimeZoneInfo.GetSystemTimeZones();
for (int i = 0; i < TimeZoneList.Count; i++)
{
Console.WriteLine(TimeZoneList[i].Id + ": " + TimeZoneList[i].SupportsDaylightSavingTime);
}
My question is, what is missing in my dateTimeToUnixTime()
method that would allow automatic adjustment and offset depending on the DST conditions?
Upvotes: 2
Views: 1731
Reputation: 5578
Assuming that your epoch starts at 1/1/1970, then we can use a DateTimeOffset
_1970
as your epoch, add the required seconds to _1970
and then use TimeZoneInfo.ConvertTime to get a date time in the specified time zone with daylight savings adjustments (if applicable). It is important to use a DateTimeOffset
and not DateTime
so that the correct offset will be kept when getting the string.
private static readonly DateTimeOffset _1970 = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
public string UnixTimeToDateTime(int unixInput, string outputFormat, string timeZoneStandardName)
{
var objTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneStandardName);
var utcDate = _1970.AddSeconds(unixInput);
DateTimeOffset localDate = TimeZoneInfo.ConvertTime(utcDate, objTimeZoneInfo);
return localDate.ToString(outputFormat);
}
//1970-01-01T13:00:00+13:00
Console.WriteLine( UnixTimeToDateTime(0, "yyyy-MM-dd'T'HH:mm:sszzz", "New Zealand Standard Time"));
//1970-01-01T08:00:00+08:00
Console.WriteLine(UnixTimeToDateTime(0, "yyyy-MM-dd'T'HH:mm:sszzz", "Singapore Standard Time"));
//1969-12-31T19:00:00-05:00
Console.WriteLine(UnixTimeToDateTime(0, "yyyy-MM-dd'T'HH:mm:sszzz", "Eastern Standard Time"));
It is important to note that using TimeZoneInfo may not have accurate information about historical date adjustments, so if that is important to you, then you may be better using a library such as Node Time.
Upvotes: 2