Getting out of the DateTime mess, or how to get Utc DateTime in C/AL

Today at work I was trying to untangle one big bowl of spaghetti called DateTime. It’s the C/AL DateTime I am talking about, not System.DateTime from .NET.

The problem with C/AL DateTime is that no matter what you do it’s, according to documentation, “always displayed as local time”.

Another problem with C/AL DateTime is that C/AL is a bit rude when it comes to System.DateTime: whenever C/AL compiler (or runtime) encounters a value of System.DateTime it’s automatically converted to C/AL DateTime.

When you combine those two problems, you get the following problem: even though System.DateTime is perfectly capable of handling time in both UTC or local kind, C/AL isn’t.

To prove this point, just run this:

MESSAGE(‘Current local time: %1\Current UTC time: %2’,SystemDateTime.Now,SystemDateTime.UtcNow);

It will show this:

image

And I am currently sitting in a UTC+1 time zone, mind you.

The particular issue I had today was to calculate Unix Time from current system time. The C# code for this is extremely simple:

However, C/AL is no friend of this. Firstly, it doesn’t allow you to call Subtract on UtcNow, because UtcNow becomes C/AL DateTime, and C/AL compiler doesn’t “see” its Subtract method. Secondly, even if it did allow me to call Subtract, it would fail because UtcNow is in fact my local time, courtesy of NAV runtime.

Thus, this is wrong:

image

So, two problems to solve here.

First problem is easily solved through reflection. I need to take the Subtract method out of the System.DateTime type:

image

To properly call Subtract we need to pass an array of arguments to the MethodInfo. Since this method receives one argument, I can do this:

image

Now, I need to assign something to the 0-index element of this array. If you say this:

image

Then this won’t work. This will return DateTime represented as local time, and we need either Utc or Unspecified kind.

One thing you can do is this:

image

Okay, now we are ready to invoke the Subtract method, however we need to specify what to subtract from. That would be current UTC date time.

I did it like this:

image

Then, finally you get the TotalSeconds property:

image

Much of this would not be required in C/AL should C/AL compiler treat System.DateTime as what it actually is, not attempting the clumsy implicit conversion to C/AL DateTime. The same problem exists for System.String and you need to get a little help from reflection to access what would (and should!) be accessible if C/AL compiler wasn’t attempting to be smarter than it should be.

9 thoughts on “Getting out of the DateTime mess, or how to get Utc DateTime in C/AL”

  1. dunno where my prev. comment is… again:
    Use DateTimeOffset instead of Datetime 🙂

    The reason is explained correctly (stumbled ofer this problem some months ago): NAV treats all times independent of the Kind-Property of DateTime-Object.

  2. Hello,

    this is my Solution:
    // XmlConvert = System.Xml.XmlConvert.’System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
    // XmlDateTimeSerializationMode = System.Xml.XmlDateTimeSerializationMode.’System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
    UTCDate := XmlConvert.ToDateTime(FORMAT(LocalNAVDate,0,9), XmlDateTimeSerializationMode.Utc);

  3. You could also make a “Old School” solution without .NET

    DTText:= FORMAT(CREATEDATETIME(TODAY,TIME),0,9);
    EVALUATE(Year,COPYSTR(DTText,1,4));
    EVALUATE(Month,COPYSTR(DTText,6,2));
    EVALUATE(Day,COPYSTR(DTText,9,2));

    _Date:= DMY2DATE(Day,Month,Year);
    EVALUATE(_Time,COPYSTR(DTText,12,5));
    _DT:= CREATEDATETIME(_Date,_Time);

Leave a Reply