Freigeben über


A Brief History of DateTime Follow-up [Anthony Moore]

Thanks all for the feedback on A Brief History of DateTime. Thanks Justin for responding to most of this. I can elaborate on some of the issues raised:

>> (3) Was there any consideration given in the design process around making DateTimeOffset an (immutable) reference type?

We did not really consider this because unless something is going to be of an unpredictable size, there is not much benefit of an immutable reference type over a value type. Also, since we wanted to replace many DateTime scenarios going forward we did not want to have a type that performed significantly differently. Can you clarify why you would prefer this design?

>> If I use DateTimeOffset, I will still need to convert it to DateTime when passing it as a parameter to existing methods. This introduces an opportunity for errors.

This might seem scary, but it should not be as problematic as it might seem. The conversions to DateTime can lose some the display time, but not the absolute point in time. Any existing API that treats the DateTime as an absolute point in time will get the right results. Once that don’t will often be subject to usage problems regardless of whether the input is a DateTime or something converted from DateTimeOffset.

>> As it is, we now filter through all source code searching for DateTime usage. Every instance is flagged as a potential bug (and usually is) needing special review

The need to do this is unfortunate, but I would agree that it is necessary with DateTime. The nice thing about DateTimeOffset is that if you can be in a world where within your own application you are using it and not DateTime, the number of usability problems is significantly reduced. Arithmetic, comparison, display and serialization all default to a behavior that is much more likely to be what it is intended. Conversions to DateTime for legacy APIs still need some checking, but there are fewer mistake opportunities than when passing in a DateTime directly.

>> A better solution is to wrap something like https://www.twinsun.com/tz/tz-link.htm.

We agonized over whether to include separate data with this functionality because we know it is important and preferable to the Windows data by many customers. It was for this reason that we ensured that the system was extensible enough that someone could populate this data into TimeZoneInfo. A challenge was that there is significant complication to everyone to dealing with multiple copies of this data when updates are needed, such as happened in the USA this year. This is something that could still be done in the future if there is sufficient demand, so we can take this as an AddRef on demand for it, but for now we did not want to default people into having a second copy of the time zone data on every machine that could create administrative problems if it got stale.

>> Any thoughts on this? If not, what is the preferred way of storing and converting back to ateTimeOffset from a SQL column?!

IIn this case you would really need to decide if you cared about knowing the absolute time as well as the offset. As discussed, most of the time you need the absolute time, so I would just use the UTC. If you do care about both and you can’t wait for the next SQL release, you would need to use an extra column, which could either be an extra DateTime (e.g. DateTimeutc+DateTimeLocal), or you could store either the local or UTC plus its offset, probably in an integer field counting the ticks, depending on which one you needed more often, although I would recommend the UTC value because then sorting the column would be meaningful.

>> What do we do with a restless trader in Singapore executing a trade through a London app online to the NASDAQ in New York, and need to ensure we execute the trade within the Quote time.. what we need is a UTCDateTime from end-to-end that is only converted to local-time when we need to display it.. Universal Time is a Universal Standard!

>> What we really need is a UtcDateTime that *is a* DateTime. That may not be possible for technical reasons (value type), but if an IDateTime interface were to be introduced and all framework signatures were updated to use the interface, both backward compatibility could be preserved and those needing a UtcDateTime would be free to use it without need for conversion. It would integrate well with the framework, too.

This is great input. I did not elaborate why we did not head further down a road like this. Another way to have solved this would be to have a type that is UTC by definition and can never be anything else, which is essentially what Win32 did. If you want to go with a model of Interface coupled with concrete types that could be UTC, you have something very close to that in Whidbey anyway, since you can have DateTime instances with Kind=Utc that you can inspect and verify that are UTC. Regardless of whether you are using this flags-based approach or using an Interface with concrete implementations, the solution is kind of ineffective. For example, in both cases public APIs that take DateTime as input have to deal with the possibility that is not the UTC input, and possibly that its time zone is completely unspecified. You can use DateTimeOffset in this manner too if you follow the convention of always using a zero offset.

There are many other problems with a type constrained to be UTC. It is hard for human beings to process in situations like debugging and inspecting persisted formats, because they have to do some math every time they want to make sense of it. Obviously when you display to a user you want to convert to a local time. Here things get tricky. You can either make this conversion happen only during formatting (e.g. a ToStringLocal()) method but then you can’t programmatically inspect sub-parts of the local instance which you need to do some times. Alternatively you can provide a local representation but to do that you either have to break the “always UTC” convention and deal with the complexity of that, or you need a whole new type just for that. Another problem is that this still does not address scenario F above where you need to work with an absolute point in time, but you also don’t want to lose what its original local value was where that might differ from the time zone on the machine.

What you ideally want is a type with the identity and reliability of a UTC Data Type without these usability down-sides. This is what DateTimeOffset is. It may not be obvious at first, but the identity, comparison and arithmetic are all based on the absolute UTC time so you get this more reliable and consistent behavior where it counts, but it also addresses the usability concerns above. The time zone offset part can be thought of as ancillary data that is not part of the value’s core identity in the same way that the trailing zeros in a Decimal values are.

Comments

  • Anonymous
    July 12, 2007
    My main issue with DateTimeOffset is that it is not a DateTime and thus does not integrate well into the framework. Specifically, it can not be used in place of a DateTime but must be converted at various points. Ideally I would like to extend DateTime, but that is not possible. The only other solution is a common interface, but then many APIs would need to be updated to take advantage of that. (Backward compatibility could be maintained, though.) For the most part, DateTimeOffset seems to have the required functionality. However, in the end I will still need to work with DateTime because it will not and can not integrate into the existing framework. Honestly, I have created my own UTC-based DateTime wrapper. However, for the exact same reasons as DateTimeOffset, it too will not integrate into the framework. This is the heart of the issue, and it is not being addressed.

  • Anonymous
    July 12, 2007
    Regarding the point about value type vs. reference type for DateTimeOffset. The reason that I would prefer a reference type is solely so that I can extend the type to my own needs (assuming it were not sealed). Making it a value type without any interfaces denies me of that. And on a similar note, I entirely agree with chronos. Because DateTimeOffset does not extend DateTime or implement any common interface, it does not fit well into the framework. It is little more than a wrapper that any of can create on our own. What we need from you, Microsoft, is a means to integrate that well into your framework. As the designers of a common framework, that should be a primary objective.

  • Anonymous
    July 14, 2007
    I agree with the above posters. The type needs to fit well into the framework. That can be done with two methods: 1) type hierarchy (via inheritance) and 2) interfaces. You are not providing either. DateTimeOffset is nothing more than a wrapper around DateTime. The type does not suit my needs very well, so I have developed my own wrapper. It fits into the framework exactly as well as DateTimeOffset (ie, not at all). Either make DateTime inheritable (somehow) or provide a common interface. Anything else does not solve the fundamental problem.

  • Anonymous
    July 14, 2007
    I need an IDateTime interface too, but for slightly different reasons. I deal with a many BC dates. Unfortunately, the design of DateTime only permits dates from January 1, 0001 and up. While I have created my own implantation, it of course does not fit into the framework, and even worse, I can not even convert it to a DateTime type when needed. DateTime is broken on so many levels. Provide us with a common IDateTime interface. Let us customize the type to our own specific needs. It was a poor design and it is time to fix it. The longer you wait, the harder it will be to deal with.

  • Anonymous
    July 15, 2007
    Thanks for the feedback everyone.  We do plan to integrate DateTimeOffset throughout the Framework where appropriate.  In .NET 3.5, we have taken the first steps by adding support for DateTimeOffset to XML Serialization and aligning the type with Microsoft SQL Server 2008.  In the next version of the Framework after .NET 3.5, we plan to integrate DateTimeOffset more thoroughly throughout the Framework adding new overloads, methods, and properties where it makes sense to do so. Thanks, Justin Van Patten CLR Program Manager

  • Anonymous
    July 15, 2007
    Justin, I do not mean to be rude, but you really are not comprehending the pains and difficulties that many of us are trying to convey.

  1. DateTimeOffset does not extend DateTime or implement a common interface. Therefore it can be used as a replacement for the broken DateTime.
  2. A default instance of DateTime is temporarily ambiguous. Ideally it should default to UTC. It can be manually set to UTC, but if ever forgotten, you have a bug which may not be so easy to find. The default DateTime is broken.
  3. Conversion to DateTime is a potential source of error. If DateTimeOffset actually was a DateTime (via extension or a common interface), then no conversion would be necessary.
  4. DateTime only allows dates from January 1st 0001. Custom types that fix this issue can not even be converted to DateTime when needed. No need for conversion if there was already a common interface.
  5. The design of DateTimeOffset does not suite some developers. Yet you leave us with options for customizing it (extension, interface). Same for DateTime.
  6. New overloads, methods, and properties for DateTimeOffset are not desired or needed. What is needed is overloads, methods, and properties for IDateTime. Along with DateTime, DateTimeOffset is a complete of epic proportions. Provide us with an IDateTime interface and start updating signatures to use it. That is the only option to fix this terrible mess. And you can even maintain complete backward compatibility at the same time.
  • Anonymous
    July 16, 2007
    The comment has been removed

  • Anonymous
    July 25, 2007
    The comment has been removed

  • Anonymous
    August 02, 2007
    The comment has been removed

  • Anonymous
    August 13, 2007
    Based on the feedback from my last CLR week , I think one CLR week a year is about right, Welcome to

  • Anonymous
    August 14, 2007
    Have you ever had to deal with consumer and provider of webservices residing in different time zones