Jasman's blog

Jasman's blog

Dynamics AX and life

Blog about life and work as an Dynamics AX developer.

Time and dates in Axapta / Dynamics AX

WorkPosted by Jacob Sørensen Tue, September 04, 2007 14:45:30

Have you ever needed to find out the amount of time (secs, hours etc.) between to dates (date and time) in Axapta / Dynamics AX (DAX) ?

I've used this approach a couple of times, and it is actually something I concieved when I was working solely with XAL-coding (the 4GL programming languange in which the Microsoft XAL and Microsoft Dynamics C5 applications are written).

Dates in Axapta / DAX are can be in the interval 01.01.1901 to 31.12.2154.
A date can be converted in to an integer with the function date2num().

Time in Axapta / DAX is represented by an integer which denotes the number of seconds since midnight. There are 86400 seconds in 24 hours. Thus it is in the interval [0,86399].

A time/integer value can be converted to the textual representation by using the function time2str();

Now the trick is to calculate the date and the time in to one value, so that if you have two points in time and want to know the diff. between them, you can calculate the numerical values and subtract them from each other.

I use the method of calculating the date and time in to seconds by doing:

Axapta 3.0 and previous


static void itsAlive(Args _args)
{
date fromdate_,todate_;
timeOfDay fromtime_,totime_;
real secondsAlive;

fromDate_ = 18\01\1971;
toDate_ = today();
fromTime_ = str2time("15:00:00"); // Three o'clock p.m.
toTime_ = timenow();

secondsAlive = (date2num(todate_)*86400+totime_) - (date2num(fromdate_)*86400+fromtime_);
info(strfmt("I have been alive for approx. %1 seconds.",secondsAlive));
info(strfmt("I have been alive for approx. %1 hours.",secondsAlive / 3600)); // Centi hours
}

NOTE that the result of the calculation of diff in seconds is stored in a real variable.
This is because of the integer data types 32 bit signed limitation in Axapta 3.0 in earlier.

This little job will calculate the amount of seconds from 18 january 1971, 3 o'clock p.m (which happens to be my birthday), to current time.

It will print the number of seconds and the number of hours since my birth.
We calculate the numbers od seconds (actually the number of seconds since 01\01\1901) by doing:

(date2num(todate_)*86400+totime_)

making it into a numerical value (datetime value) that can be used for calculations.

By dividing the number of seconds by 3600 (which is the number of seconds in a hour) we get the value in (centi) hours.

This could be used for say:

Calculating the numbers of hours worked for billing.
Calculating the duration of a phone call for billing
Calculating the duration of a ship's stay in harbour for billing.
Etc

To go from a datetime-value back to date and time you can do:

static void back2datetime(Args _args)
{
real datetimevalue = (date2num(18\01\1971)*86400.00)+str2time('15:00:00');
// 2243289600 seconds;
date dateresult;
real days;
timeOfDay timeresult;
;

days = datetimevalue / 86400;
dateresult = num2date(days); // Important that it is a REAL or the daynumbers overflow
timeresult = datetimevalue - trunc(days) * 86400; // Which is actually datetimevalue MOD 86400


info(strfmt("The datetimevalue yields date: %1 %2 o'clock.",dateresult,time2str(timeresult,1,1)));

}

It is important that when initializing datetimevalue you multiply the daynumber with 86400.00. If you multiply by the integer 86400 without the zero fraction, the kernel converts the result of the multiplication to an integer causing a wrong result.

The reason why you can not do datetimevalue MOD 86400 is because of precision loss caused by the MOD operator which converts to datetimevalue to an integer causing a wrong result.


There is a slight difference in the way this is done in Axapta 3.0 and previous and Dynamics AX 4.0.

In Axapta 3.0 the integers are signed 32-bit integers (long) which means that the value of an integer variable is in the interval [-2,147,483,648 to 2,147,483,647].

In DAX 4.0 int64 was introduced, this means that we can actually use the true DIV and MOD operators.

This is the job to calculate the diff in seconds and hours between dates:
DAX 4.0 code:

static void itsAlive4_0(Args _args)
{
date fromdate_,todate_;
timeOfDay fromtime_,totime_;
real secondsAlive;
real datetimevalue;
int64 bigint;

date dateresult;
real days;
timeOfDay timeresult;


fromDate_ = 18\01\1971;
toDate_ = today();
fromTime_ = str2time("15:00:00"); // Three o'clock p.m.
toTime_ = timenow();

secondsAlive = (date2num(todate_)*86400.00+totime_) - (date2num(fromdate_)*86400.00+fromtime_);
info(strfmt("I have been alive for approx. %1 seconds.",secondsAlive));
info(strfmt("I have been alive for approx. %1 hours.",secondsAlive div 3600)); // Centi hours
}

This is the job to go back from seconds to date and time re-written for DAX 4.0:
DAX 4.0 code:


static void back2datetime4_0(Args _args)
{
date dateresult;
timeOfDay timeresult;
int64 bigint;
;

bigint = (date2num(18\01\1971)*86400.00+str2time('15:00:00'));
dateresult = num2date(bigint div 86400); // Important that it is a REAL or the daynumbers overflow
timeresult = bigint mod 86400; // Which is actually datetimevalue MOD 86400

info(strfmt("The datetimevalue yields date: %1 %2 o'clock.",dateresult,time2str(timeresult,1,1)));
}

  • Comments(0)//blog.fasor.dk/#post41