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:
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:
var unixTime = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
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:
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:
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:
Now, I need to assign something to the 0-index element of this array. If you say this:
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:
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:
Then, finally you get the TotalSeconds property:
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.