gchq
gchq

Reputation: 1775

TimeZone issue with Windows 7

When a date is returned from our UTC server database Windows very helpfully changes the Date to a DateTime (say 23 June 2017 to 2017-06-23 00:00) and then makes an adjustment for the current Time Zone (to, say 2017-06-22 16:00)... For years we have used the code below to convert it back...

About four months ago users running Windows 7 (Windows 10 doesn't seem to be effected) that did not have 'Automatically adjust clock for Daylight Saving Time' checked, or live in a state like Arizona where that option is not available, noticed that reports where returning the date from the day before - our DB is returning the correct date but the conversion is no longer working correctly..

Any suggestions?

Thanks

Public Function LocalDateFormat(ByVal InputDate As Date) As String
    Dim vDate As String = InputDate.ToString("d", System.Globalization.CultureInfo.InvariantCulture)
    Dim LocalZone As TimeZone = TimeZone.CurrentTimeZone
    Dim CurrentOffset As TimeSpan = LocalZone.GetUtcOffset(InputDate)
    Dim DayLightSaving As Boolean = LocalZone.IsDaylightSavingTime(InputDate)
    Dim CalculatedOffset As New DateTime(InputDate.Ticks, DateTimeKind.Local)
    If CurrentOffset.CompareTo(TimeSpan.Zero) < 0 Then
        CalculatedOffset -= LocalZone.GetUtcOffset(InputDate)
        If DayLightSaving = True Then
            CalculatedOffset = CalculatedOffset.AddHours(1)
        End If
    Else
        CalculatedOffset += LocalZone.GetUtcOffset(InputDate)
        If DayLightSaving = True Then
            CalculatedOffset = CalculatedOffset.AddHours(-1)
        End If
    End If

    InputDate = CalculatedOffset

    Dim vCulture As String = System.Globalization.CultureInfo.CurrentCulture.ToString
    Dim vReturnDate As String = ""
    Select Case vCulture
        Case "en-US"
            vReturnDate = Format(InputDate, "MM/dd/yyyy")
        Case "en-GB"
            vReturnDate = Format(InputDate, "dd/MM/yyyy")
        Case Else
            vReturnDate = Format(InputDate, "dd/MM/yyyy")
    End Select
    Return vReturnDate

End Function

Upvotes: 1

Views: 134

Answers (1)

Matt Johnson-Pint
Matt Johnson-Pint

Reputation: 241920

Your entire function can be re-written as:

Public Function LocalDateFormat(ByVal InputDate As Date) As String
    Return InputDate.ToLocalTime().ToShortDateString()
End Function

With the code so small, you may want to rethink whether there's any benefit of having this in a function at all.

As far as why your existing function didn't work properly:

  • TimeZone.GetUtcOffset already factors in whether DST is in effect or not, though it has some problems with that that are described in the MSDN docs.
  • You shouldn't be using TimeZone any more at all. If you need to work with time zones, use TimeZoneInfo, or Noda Time. In this case, you don't need either of them, as you're just converting from UTC to local time, which is what DateTime.ToLocalTime does.
  • This code has some logic that appears to think one should subtract an hour for DST if the offset is positive. Sorry, but DST doesn't work that way - you always add an hour (unless you are in Lord Howe Island, Australia, where you add 30 minutes).
  • It also seems to think you should add the offset from UTC if its positive and subtract it if its negative. This is essentially an absolute value function, and also incorrect.
  • All the culture stuff is handled for you by formatting within the current culture. There's no need to do it by hand.

You say it works fine on Windows 10, but I'm sorry - this is bad code that will have errors wherever it is run. Just use the built-in APIs provided by the framework. Don't reinvent the wheel. :)

Upvotes: 1

Related Questions