DateTimeOffset: A New DateTime Structure in .NET 3.5 [Justin Van Patten]

DateTimeOffset: A New DateTime Structure in .NET 3.5 [Justin Van Patten]

Rate This
  • Comments 18

One thing we haven't publicized much on this blog yet is a new date time structure we've added in .NET 3.5 called DateTimeOffset (currently available as part of .NET Framework 3.5 Beta 1).  Kathy mentioned it on her blog a while back and Daniel Moth recently posted about it as well.

DateTimeOffset

DateTimeOffset is a new date time data structure that specifies an exact point in time relative to the UTC time zone.  It is made up of a date time and offset relative to the UTC time zone.  DateTimeOffset includes most of the functionality of the current DateTime and allows seamless conversion to DateTime.  DateTimeOffset also works great with TimeZoneInfo which is also new in .NET 3.5.

Samples

1. Creating a new DateTimeOffset:

DateTimeOffset now = DateTimeOffset.Now;

DateTimeOffset now2 = DateTime.Now;

DateTimeOffset now3 = new DateTimeOffset(DateTime.Now);

 

 

DateTime tvShowPremiere = new DateTime(2007, 6, 13, 8, 0, 0);

DateTimeOffset tvShowPremiereUTC = new DateTimeOffset(tvShowPremiere.ToUniversalTime());

DateTimeOffset tvShowPremiereLA = new DateTimeOffset(tvShowPremiere, new TimeSpan(-7, 0, 0));

DateTimeOffset tvShowPremiereNYC = new DateTimeOffset(tvShowPremiere, new TimeSpan(-4, 0, 0));

DateTimeOffset tvShowPremiereLocal = tvShowPremiere; // implicit cast

 

 

DateTimeOffset utcNewYear07 = new DateTimeOffset(2007, 1, 1, 0, 0, 0,

                                new TimeSpan(0, 0, 0));

DateTimeOffset seattleNewYear07 = new DateTimeOffset(2007, 1, 1, 0, 0, 0,

                                    new TimeSpan(-8, 0, 0));

2. Converting a DateTimeOffset to a DateTime:

DateTime dtSeatleNewYear07Utc = seattleNewYear07.UtcDateTime;

DateTime dtSeattleNewYear07Local = seattleNewYear07.LocalDateTime;

3. Parsing a DateTimeOffset:

DateTimeOffset dateA = DateTimeOffset.Parse("4/15/2006 6:00 AM -7:00");

DateTimeOffset dateB = DateTimeOffset.Parse("4/15/2006 6:00:00 AM -7:00");

DateTimeOffset dateC = DateTimeOffset.Parse("-7:00 4/15/2006 6:00 AM");

DateTimeOffset dateD = DateTimeOffset.Parse("4/15/2006 -7:00 6:00 AM");

Usage Guidance

Anthony Moore has some guidance on when to use DateTimeOffset vs. DateTime:

  • Use DateTimeOffset whenever you are referring to an exact point in time.  For example, use it to calculate "now", transaction times, file change times, logging event times, etc.  If the time zone is not known, use it with UTC.  These uses are much more common than the scenarios where DateTime is preferred, so this should be considered the default.
  • Use DateTime for any cases where the absolute point in time does not apply: e.g. store opening times that apply across time zones.
  • Use DateTime for interop scenarios where the information is a Date and Time without information about the time zone, e.g. OLE Automation, databases, existing .NET APIs that use DateTime, etc.
  • Use DateTime with a 00:00:00 time component to represent whole dates, e.g. Date of birth.
  • Use TimeSpan to represent times of day without a date.

As you can see, DateTimeOffset is the new preferred type to use for the most common date time scenarios.  Future BCL APIs will incrementally start to use and take advantage of DateTimeOffset where it makes sense.  This doesn't mean DateTimeOffset is meant to be a replacement for DateTime—DateTime is still useful in the scenarios mentioned above.

  • What's wrong with just using DateTime to refer to UTC? In all our code we have DateTime, and it's always UTC (as is the timezone on all our servers). What am I missing?

  • Microsoft,

    This DateTimeOffset type will not be sufficient. I need a DateTime (ie, something that extends DateTime), not something that can convert into a DateTime.

    Please unseal the type and I will do the work myself.

  • chronos, DateTime is a structure and thus cannot be inherited.

  • Then we need an IDateTime interface and _all_ signatures taking a DateTime will need to be depreciated and replaced.

  • I always use DateTime.UtcNow whenever I'm referring to an exact point in time.

  • Axel,

    As do I. However, I have debugged code where specifying UTC was occasionally forgotten. It was a timely and expensive fix.

    I want it to always be in UTC. Nor do I want to worry that my team will get it right. Why should I always need to make the same settings every time? A UTC-only type would be much more desired.

    DateTimeOffset only complicates the situation further and is not an ideal solution. I agree that an IDateTime interface is needed.

  • Paul,

    > DateTime is a structure and thus

    > cannot be inherited.

    In C# that is true, but certainly not in all other languages. Try to compile the following IL into a DLL.

    .assembly Testing {}

    .namespace Foo

    {

       .class public sequential unicode sealed beforefieldinit MyStruct

           extends [mscorlib]System.ValueType

       {

       }

       .class public sequential unicode sealed beforefieldinit MyStruct2

           extends [mscorlib]System.ValueType

           implements Foo.MyStruct

       {

       }

    }

    You may then use it from C#. (And I encourage you to examine the DLL in Reflector.)

    There really is a strong need for a UTC-only DateTime type. Unsealing the type would be sufficient as I am comfortable writing IL. However, an interface is ultimately the better option. All of these new types being added in Orcas is only adding further complication without truely solving the real problem.

  • Not very good IL. This is better:

    .assembly Testing {}

    .namespace Foo

    {

       .class public sequential unicode beforefieldinit MyStruct

           extends [mscorlib]System.ValueType

       {

         .method public hidebysig virtual instance void BaseMethod() cil managed

         {

           ret

         }

       }

       .class public sequential unicode sealed beforefieldinit MyStruct2

           extends Foo.MyStruct

       {

       }

    }

    However, when used in C#, the compiler throws CS0648 (type not supported by the language). It's legal IL, so C# should just consume it.

    In any case, an IDateTime interface is really needed and is the best long-term solution.

  • >> In any case, an IDateTime interface is really needed and is the best long-term solution.

    I disagree. Better to make a clear distinction between the two types as has been suggested in the post.

  • Matthew,

    A default DateTime is broken 100% of the time. Every single time it will need to be manually set to be UTC. Any exceptions, probably accidental, and often even due to ignorance or poor design, is a bug to be found and fixed. I have fixed dozens of these bugs over the last six years at several different companies. I have created wrapper types to help solve the problem. However, the best that can be done is wrap DateTime because it can not be extended and there are no interfaces to implement. I have also created my own non-wrapper types that provide the necessary functionality. However, it does not fit into the framework because of incompatible signatures.

    While I have had many unpleasent encounters with this type in particular, the source of the problem is very prevalent throughout the BCL: 1) sealed types and 2) no interfaces. You can do better than this.

    I am perfectly fine if Microsoft does not want to provide the functionality. But let me. To integrate that into the BCL, though, I will need to be able to either extend the type or implement an interface (appropriate signatures will need to take interface, the implementation).

  • Will DataSets support DateTimeOffset ?

    We currently have the DateTimeMode property to control serialization of dateTimes from datasets. Although it has limitations, like you can't set it after you've loaded any rows, so it's a pain for untyped datasets - need to call FillSchema then Fill. And there were bugs with typed datasets - some claim these still aren't fixed in SP1 - see http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=208033&SiteID=1

    So, will Datasets allow columns of type DateTimeOffset ? How would that work for untyped datasets where columns are created on the fly based on the SQL statement - do we need a "create dateTimes as DateTimeOffset's" property ? And could we specify a default timezone like UTC, or allow that to be picked up from a database column ? Whilst Oracle has a timestamp with timezone datatype which could map straight to DateTimeOffset, SQL Server doesn't, so how could we set default timezones in that case ?

    I don't want to get into discussion about whether datasets are evil or not (personally I use objects) but lots of developers do use datasets, so it needs considering.

  • Magari non è uno dei massimi problemi per chi lavora in Europa e generalmente ha a che fare con un solo

  • >> Justin Van Patten

    Nope, that IL is not valid nor its metadata.

    ILAsm compiles your Foo valuetype as sealed (even you do not mark it as sealed). If you compile it with "The Monster Flag" (/errors), you can create an unsealed value type. BUT such metadata are invalid. I hope Loader will refuse the assembly...

  • " Anthony Moore has some guidance on when to use DateTimeOffset vs. DateTime: Use DateTimeOffset whenever...

  • Visual Studio (VS) 2008 and .Net 3.5, code named “Orcas”, will be released in the near future. This release

Page 1 of 2 (18 items) 12