System.TimeZone interface unusable?

N

nosiren

It is well known that the implementation of time zones other than the
machine local time zone has been left as an exercise for the user in
the .NET framework. It would seem that System.TimeZone, being an
abstract class, is meant to be used as a base class for any such
implementations. Having thoroughly reviewed the MSDN documentation for
System.TimeZone it would seem that, especially considering the new
DateTime.Kind property, System.TimeZone is actually unusable as a base
class.

Previously, although the MSDN documentation suggested otherwise, I had
to believe that the spirit of ToLocalTime() was to return a time that
was local to the particular time zone instance being used. This belief
was strengthened by the shared source implementation Microsoft provided
in 2002, and has been shared by any implementation I have seen that
uses System.TimeZone as a base class (see
http://www.michaelbrumm.com/simpletimezone.html for one example).

The addition of DateTime.Kind in .NET 2.0 has proven this belief to be
incorrect. ToLocalTime() must by contract always return machine local
time.

Here's an experiment. Fully implement the System.TimeZone abstract
interface for any time zone other than your own. Now set a breakpoint
in all of your methods and call TimeZone.ToLocalTime() for DateTimes of
Local, Utc, and Unspecified DateTime.Kind. You should discover, as I
did, that your code never gets called. Now try
TimeZone.ToUniversalTime() for the same values. Interestingly,
ToUniversalTime() WILL call your code for both Local and Unspecified
DateTime.Kind values. Make sense of that.

I just want to understand what the purpose of System.TimeZone really
is. If it were sealed, and all of its methods made static, it seems it
would lose no utility whatsoever. Am I missing something?

Any discussion would be appreciated.
 
J

Jay B. Harlow [MVP - Outlook]

Nosiren,
| System.TimeZone it would seem that, especially considering the new
| DateTime.Kind property, System.TimeZone is actually unusable as a base
| class.
Using ILDASM, it appears that TimeZone.ToLocalTime in .NET 2.0 is hard wired
to a concrete implementation class. IMHO a very bad no no in OO (rhyme not
really intended).

I understand that they are still accepting bug reports & feature requests at
http://lab.msdn.microsoft.com/ProductFeedback/.



You should be able to override TimeZone.ToLocalTime itself and have the
behavior you expect. Something like:

Public Class MyTimeZone
Inherits TimeZone

...

Public Overrides Function ToLocalTime(ByVal time As DateTime) As
DateTime
If time.Kind = DateTimeKind.Local Then
Throw New ArgumentOutOfRangeException("time.Kind",
time.Kind, "DateTime is already Local time!")
End If
Return time + GetUtcOffset(time)
End Function

...

End Class

However the above doesn't seem to work as I would expect...

The quirk/caveat is going to be what to do with DateTimeKind.Local on input
to MyTimeZone.ToLocalTime. My sample only allows Utc or Unspecified date
time values, as the parameter states "a UTC time". Considering that the time
parameter maybe in a different time zone then the this time zone, IMHO the
exception is the "better" choice. Alternative if the input is already Local
then one could simply return it "As is", as its already local...

http://msdn2.microsoft.com/en-us/library/system.timezone.tolocaltime.aspx

--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| It is well known that the implementation of time zones other than the
| machine local time zone has been left as an exercise for the user in
| the .NET framework. It would seem that System.TimeZone, being an
| abstract class, is meant to be used as a base class for any such
| implementations. Having thoroughly reviewed the MSDN documentation for
| System.TimeZone it would seem that, especially considering the new
| DateTime.Kind property, System.TimeZone is actually unusable as a base
| class.
|
| Previously, although the MSDN documentation suggested otherwise, I had
| to believe that the spirit of ToLocalTime() was to return a time that
| was local to the particular time zone instance being used. This belief
| was strengthened by the shared source implementation Microsoft provided
| in 2002, and has been shared by any implementation I have seen that
| uses System.TimeZone as a base class (see
| http://www.michaelbrumm.com/simpletimezone.html for one example).
|
| The addition of DateTime.Kind in .NET 2.0 has proven this belief to be
| incorrect. ToLocalTime() must by contract always return machine local
| time.
|
| Here's an experiment. Fully implement the System.TimeZone abstract
| interface for any time zone other than your own. Now set a breakpoint
| in all of your methods and call TimeZone.ToLocalTime() for DateTimes of
| Local, Utc, and Unspecified DateTime.Kind. You should discover, as I
| did, that your code never gets called. Now try
| TimeZone.ToUniversalTime() for the same values. Interestingly,
| ToUniversalTime() WILL call your code for both Local and Unspecified
| DateTime.Kind values. Make sense of that.
|
| I just want to understand what the purpose of System.TimeZone really
| is. If it were sealed, and all of its methods made static, it seems it
| would lose no utility whatsoever. Am I missing something?
|
| Any discussion would be appreciated.
|
 
N

nosiren

Hi Jay,

Thanks for the reply.
Using ILDASM, it appears that TimeZone.ToLocalTime in .NET 2.0 is hard wired
to a concrete implementation class. IMHO a very bad no no in OO.

My thoughts exactly.
You should be able to override TimeZone.ToLocalTime itself and have the
behavior you expect.

I would say this is true, but I have to consider the contract of the
base class. According to the MSDN documentation, the return value of
ToLocalTime must be "A DateTime instance whose value is the local time
that corresponds to time... Local time is the date and time on the
computer you are using." Therefore, overriding ToLocalTime to return
anything other than machine local time breaks the contract for
ToLocalTime, and will cause incorrect results for someone expecting the
documented base class behavior.
The quirk/caveat is going to be what to do with DateTimeKind.Local on input
to MyTimeZone.ToLocalTime. My sample only allows Utc or Unspecified date
time values, as the parameter states "a UTC time". Considering that the time
parameter maybe in a different time zone then the this time zone, IMHO the
exception is the "better" choice. Alternative if the input is already Local
then one could simply return it "As is", as its already local...

The definition of Local throughout MSDN still seems to be machine local
time, so although there are problems as you have specified, they are
different than you have mentioned. Most notably, any DateTime that is
not UTC or machine local time must have a Kind of
DateTimeKind.Unspecified. Regardless, it seems perfectly sensible for
ToLocalTime() to assume a UTC parameter and for ToUniversalTime() to
take a "native time" parameter (avoiding the phrase "local time" for
obvious reasons). Personally, I suspect that the addition of
DateTime.Kind to the framework was not for the benefit of the TimeZone
class at all.

It's my understanding that, prior to .NET 2.0, the XML Serializer made
the fundamentally flawed assumption that all outoing dates were in
machine local time and all incoming dates were in UTC. Since the
serializer documentation is the only other place the Kind property is
mentioned, I have to conclude that DateTime, a core component of the
framework IMHO, has been hijacked to fix mistakes made in the XML
Serializer. If that is true, then this really is a nasty little hack.
Even the new documentation for DateTime reads like raw hackery: "Prior
to the .NET Framework version 2.0, the DateTime structure contains a
64-bit field composed of an unused 2-bit field concatenated with a
private Ticks field." You can almost hear Jon Lovitz saying, "I meant
to do that... yeah, that's the ticket."

As it stands, I've pretty much concluded that the documented interface
for System.TimeZone is fundamentally broken, and am moving on with my
own base class with a similar interface but a more sensible contract.

Thanks,

Russ
 
J

Jay B. Harlow [MVP - Outlook]

| ToLocalTime must be "A DateTime instance whose value is the local time
| that corresponds to time... Local time is the date and time on the
| computer you are using." Therefore, overriding ToLocalTime to return
| anything other than machine local time breaks the contract forI
I interpret "local time" as local to the "current" Time Zone. Currently
"current" Time Zone is TimeZone.CurrentZone. If you create a TimeZone object
then that object is the "current" Time Zone.

Although I agree with the gest of your comments. The documentation is
misleading, so the method cannot be truely implemented correctly.

| The definition of Local throughout MSDN still seems to be machine local
Ah! There's the rub! "seems to be", "local time" really needs to be defined
better in relation to what, especially when you start deriving classes...


--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Hi Jay,
|
| Thanks for the reply.
|
| > Using ILDASM, it appears that TimeZone.ToLocalTime in .NET 2.0 is hard
wired
| > to a concrete implementation class. IMHO a very bad no no in OO.
|
| My thoughts exactly.
|
| > You should be able to override TimeZone.ToLocalTime itself and have the
| > behavior you expect.
|
| I would say this is true, but I have to consider the contract of the
| base class. According to the MSDN documentation, the return value of
| ToLocalTime must be "A DateTime instance whose value is the local time
| that corresponds to time... Local time is the date and time on the
| computer you are using." Therefore, overriding ToLocalTime to return
| anything other than machine local time breaks the contract for
| ToLocalTime, and will cause incorrect results for someone expecting the
| documented base class behavior.
|
| > The quirk/caveat is going to be what to do with DateTimeKind.Local on
input
| > to MyTimeZone.ToLocalTime. My sample only allows Utc or Unspecified date
| > time values, as the parameter states "a UTC time". Considering that the
time
| > parameter maybe in a different time zone then the this time zone, IMHO
the
| > exception is the "better" choice. Alternative if the input is already
Local
| > then one could simply return it "As is", as its already local...
|
| The definition of Local throughout MSDN still seems to be machine local
| time, so although there are problems as you have specified, they are
| different than you have mentioned. Most notably, any DateTime that is
| not UTC or machine local time must have a Kind of
| DateTimeKind.Unspecified. Regardless, it seems perfectly sensible for
| ToLocalTime() to assume a UTC parameter and for ToUniversalTime() to
| take a "native time" parameter (avoiding the phrase "local time" for
| obvious reasons). Personally, I suspect that the addition of
| DateTime.Kind to the framework was not for the benefit of the TimeZone
| class at all.
|
| It's my understanding that, prior to .NET 2.0, the XML Serializer made
| the fundamentally flawed assumption that all outoing dates were in
| machine local time and all incoming dates were in UTC. Since the
| serializer documentation is the only other place the Kind property is
| mentioned, I have to conclude that DateTime, a core component of the
| framework IMHO, has been hijacked to fix mistakes made in the XML
| Serializer. If that is true, then this really is a nasty little hack.
| Even the new documentation for DateTime reads like raw hackery: "Prior
| to the .NET Framework version 2.0, the DateTime structure contains a
| 64-bit field composed of an unused 2-bit field concatenated with a
| private Ticks field." You can almost hear Jon Lovitz saying, "I meant
| to do that... yeah, that's the ticket."
|
| As it stands, I've pretty much concluded that the documented interface
| for System.TimeZone is fundamentally broken, and am moving on with my
| own base class with a similar interface but a more sensible contract.
|
| Thanks,
|
| Russ
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top