I've seen that many websites (usually forums) allow users to specify their TimeZone preferences by selecting:
- the TimeZone
- whether or not to use DST
As far as I know, when doing conversions, .NET always takes DST into account, so the question is:
How can the "do not use DST" part be implemented in C#?
Below this point I present what I managed to do so far, but it feels hacky and I was wondering if there was a cleaner/better approach.
First, to make sure that DST is applied automatically, I wrote the following test:
[Test]
public void DateTimeConversion_ToLocalTime_HandlesDSTByDefault()
{
var utcDateInDstInterval = new DateTime(2012, 07, 15, 0, 0, 0, DateTimeKind.Utc);
var utcDateOutisdeDstInterval = new DateTime(2012, 02, 15, 0, 0, 0, DateTimeKind.Utc);
var roTimezone = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time");
Assert.AreEqual(3, TimeZoneInfo.ConvertTimeFromUtc(utcDateInDstInterval, roTimezone).Hour);
Assert.AreEqual(2, TimeZoneInfo.ConvertTimeFromUtc(utcDateOutisdeDstInterval, roTimezone).Hour);
}
This test passes, showing that:
- when no DST applies (for example in winter) the Romanian time is UTC + 2 hours
- when DST applies (for example in summer) the Romanian time is UTC + 3 hours
- when doing DateTime conversions, DST is automatically taken into account
Next, I noticed the TimeZoneInfo.GetAdjustmentRules()
method that returns an array of AdjustmentRule
objects and figured out that if I undo the effects of these rules I could get the DST-unaffected value.
So I wrote the following method that does this if the DateTime
object is affected by DST:
private DateTime RemoveDSTFromDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)
{
if (!dateTime.IsDaylightSavingTime())
return dateTime;
var result = dateTime;
foreach (var adjustmentRule in timeZoneInfo.GetAdjustmentRules())
result = result.Subtract(adjustmentRule.DaylightDelta);
return result;
}
Back to the original DST/No DST scenario, but this time forcing the result to be unaffected by DST:
[Test]
public void DateTimeConversion_ToLocalTime_WithoutDST()
{
var utcDateInDstInterval = new DateTime(2012, 07, 15, 0, 0, 0, DateTimeKind.Utc);
var utcDateOutisdeDstInterval = new DateTime(2012, 02, 15, 0, 0, 0, DateTimeKind.Utc);
var roTimezone = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time");
var convertedDateWithDst = TimeZoneInfo.ConvertTimeFromUtc(utcDateInDstInterval, roTimezone);
var convertedDateWithoutDst = TimeZoneInfo.ConvertTimeFromUtc(utcDateOutisdeDstInterval, roTimezone);
Assert.AreEqual(2, RemoveDSTFromDateTime(convertedDateWithDst, roTimezone).Hour);
Assert.AreEqual(2, RemoveDSTFromDateTime(convertedDateWithoutDst, roTimezone).Hour);
}
This test also passes, showing that now the effect of DST is cancelled (we always get UTC + 2h, regardless of the time of the year).
While writing this down I got another idea that appears to work: instead of using any TimeZoneInfo.Convert...()
methods, simply add roTimezone.BaseUtcOffset
to the UTC date.
Can anyone indicate what is the right way to do this?