Joe Cincotta: Thoughts and such…

Icon

Nerdism for the masses.

.NET Generic TimeZone Management

Ever wondered how the hell you can have a ‘live’ timezone which understands its own daylight savings rules and handles localization without having to use .Net globalization?

The usual circumstance where this problem manifests itself is when deploying time sensitive applications on web servers. If you can store some simple timezone region info (a timezone label) for each user then you can perform locale agnostic conversions for the user as long as you store all your times as UTC… Just look up the label and use the TimeZoneFactory to create your timezone.

Use an XML datafile to popultate the TimeZone objects through the Factory. You can even have a RealTimeZone ListItemCollection helper for binding a list of RealTimeZones to a combo box.

Here is the core class without the creation factories – (ie: this is the hard part!):


Public Class RealTimeZone
  Inherits System.TimeZone

  Private Sub New()
  End Sub

  Private _GenericName As String
  Private _DaylightOffset As Integer
  Private _StandardOffset As Integer
  Private _DaylightStartMonthUTC As Integer
  Private _DaylightStartDayUTC As Integer
  Private _DaylightStartHourUTC As Integer
  Private _DaylightEndMonthUTC As Integer
  Private _DaylightEndDayUTC As Integer
  Private _DaylightEndHourUTC As Integer
  Private _DaylightName As String
  Private _StandardName As String

  Protected Friend Sub New(ByVal GenericName As String, ByVal DaylightOffset As Integer, ByVal StandardOffset As Integer, ByVal DaylightStartMonthUTC As Integer, ByVal DaylightStartDayUTC As Integer, ByVal DaylightStartHourUTC As Integer, ByVal DaylightEndMonthUTC As Integer, ByVal DaylightEndDayUTC As Integer, ByVal DaylightEndHourUTC As Integer, ByVal DaylightName As String, ByVal StandardName As String)
    Me._GenericName = GenericName
    Me._DaylightOffset = DaylightOffset
    Me._StandardOffset = StandardOffset
    Me._DaylightStartMonthUTC = DaylightStartMonthUTC
    Me._DaylightStartDayUTC = DaylightStartDayUTC
    Me._DaylightStartHourUTC = DaylightStartHourUTC
    Me._DaylightEndMonthUTC = DaylightEndMonthUTC
    Me._DaylightEndDayUTC = DaylightEndDayUTC
    Me._DaylightEndHourUTC = DaylightEndHourUTC
    Me._DaylightName = DaylightName
    Me._StandardName = StandardName
  End Sub

  Public ReadOnly Property GenericName() As String
    Get
      Return Me._GenericName
    End Get
  End Property

  Public Function RenderLocalTime(ByVal UTCTime As DateTime, ByVal timeFormat As String) As String
    Dim ot As DateTime = UTCTime.AddHours(GetUtcOffset(UTCTime).TotalHours)
    Return ot.ToString(timeFormat)
  End Function

  Public Function ConvertToLocalTime(ByVal SourceUniversalTime As DateTime) As DateTime
    Return SourceUniversalTime.AddHours(GetUtcOffset(SourceUniversalTime).TotalHours)
  End Function

  Public Function ConvertFromLocalTime(ByVal SourceLocalTime As DateTime) As DateTime
    Return SourceLocalTime.AddHours((GetUtcOffset(SourceLocalTime).TotalHours * -1))
  End Function

  Public Function GetUTCDayStart(ByVal Year As Integer, ByVal Month As Integer, ByVal Day As Integer) As DateTime
    Dim target As New DateTime(Year, Month, Day, 0, 0, 0)
    Return ConvertFromLocalTime(target)
  End Function

  Public Function GetUTCDayEnd(ByVal Year As Integer, ByVal Month As Integer, ByVal Day As Integer) As DateTime
    Dim target As New DateTime(Year, Month, Day, 23, 59, 59)
    Return ConvertFromLocalTime(target)
  End Function

  Public Function GetUTCDayStart(ByVal LocalDate As DateTime) As DateTime
    Dim target As New DateTime(LocalDate.Year, LocalDate.Month, LocalDate.Day, 0, 0, 0)
    Return ConvertFromLocalTime(target)
  End Function

  Public Function GetUTCDayEnd(ByVal LocalDate As DateTime) As DateTime
    Dim target As New DateTime(LocalDate.Year, LocalDate.Month, LocalDate.Day, 23, 59, 59)
    Return ConvertFromLocalTime(target)
  End Function

  Public Overrides Function GetDaylightChanges(ByVal year As Integer) As System.Globalization.DaylightTime
    Dim sdUTC As New DateTime(year, Me.DaylightStartMonthUTC, Me.DaylightStartDayUTC, Me.DaylightStartHourUTC, 0, 0)
    Dim edUTC As New DateTime(year, Me.DaylightEndMonthUTC, Me.DaylightEndDayUTC, Me.DaylightEndHourUTC, 0, 0)
    Return New System.Globalization.DaylightTime(System.TimeZone.CurrentTimeZone.ToLocalTime(sdUTC), System.TimeZone.CurrentTimeZone.ToLocalTime(edUTC), New TimeSpan(1, 0, 0))
  End Function

  Public Overloads Overrides Function GetUtcOffset(ByVal time As Date) As System.TimeSpan
    Dim dt As System.Globalization.DaylightTime = GetDaylightChanges(time.Year)
    Dim cmpStart As Integer = time.CompareTo(dt.Start)
    Dim cmpEnd As Integer = time.CompareTo(dt.End)
    If (cmpStart >= 0) And (cmpEnd     Return New TimeSpan(Me.StandardOffset, 0, 0)
  End Function

  Public Overloads Function GetUtcOffset() As System.TimeSpan
    Return GetUtcOffset(DateTime.UtcNow)
  End Function

  Public ReadOnly Property DaylightOffset() As Integer
    Get
      Return Me._DaylightOffset
    End Get
  End Property

  Public ReadOnly Property StandardOffset() As Integer
    Get
      Return Me._StandardOffset
    End Get
  End Property

  Public ReadOnly Property DaylightStartMonthUTC() As Integer
    Get
      Return Me._DaylightStartMonthUTC
    End Get
  End Property

  Public ReadOnly Property DaylightStartDayUTC() As Integer
    Get
      Return Me._DaylightStartDayUTC
    End Get
  End Property

  Public ReadOnly Property DaylightStartHourUTC() As Integer
    Get
      Return Me._DaylightStartHourUTC
    End Get
  End Property

  Public ReadOnly Property DaylightEndMonthUTC() As Integer
    Get
      Return Me._DaylightEndMonthUTC
    End Get
  End Property

  Public ReadOnly Property DaylightEndDayUTC() As Integer
    Get
      Return Me._DaylightEndDayUTC
    End Get
  End Property

  Public ReadOnly Property DaylightEndHourUTC() As Integer
    Get
      Return Me._DaylightEndHourUTC
    End Get
  End Property

  Public Overrides ReadOnly Property DaylightName() As String
    Get
      Return Me._DaylightName
    End Get
  End Property

  Public Overrides ReadOnly Property StandardName() As String
    Get
      Return Me._StandardName
    End Get
  End Property
End Class

Advertisement

Filed under: Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.