23 March 2015

What Date and DateTime does kernel use for valid time state tables

I had to check whether a record in valid time state table is valid now and I got curious about what Date and DateTime values are actually used by kernel.  The answer seemed to be obvious, but in fact it was not. Please find the details below.

Problem description
There are several cases when kernel generates values for valid time state tables:
- ValidFrom field default value set by kernel when a new record is created
- ValidFrom and ValidTo ranges added by kernel into a select statement.
Let's analyse them.

Questions to analyse
1. Is session date and time used?
2. Is client machine date and time used?
3. Is user time zone used?

Hints
Create two valid time state tables with ValidTimeStateFieldType property set to Date and UtcDateTime. Try to change session date and time, client machine date and time, user time zone and compare default values of new record in different cases.


Solution

For Date valid time state table the following value is used by kernel: DateTimeUtil::date(DateTimeUtil::applyTimeZoneOffset(DateTimeUtil::utcNow(), DateTimeUtil::getUserPreferredTimeZone()))

For UtcDateTime valid time state table the following value is used by kernel:
DateTimeUtil::utcNow()

I created two valid time state tables:
- TestDate with ValidTimeStateFieldType set to Date
- TestDateTime with ValidTimeStateFieldType set to UtcDateTime.
The following job was used for select statements analysis:
static void TestDateTime(Args _args)
{
    TestDate        testDate;
    TestDateTime    testDateTime;

    select generateonly forceLiterals RecId from testDate;
    select generateonly forceLiterals RecId from testDateTime;

    info(testDate.getSQLStatement());
    info(testDateTime.getSQLStatement());
}

Initial setup
Client machine date was: 22.03.2015, time zone: UTC+01:00, user time zone: UTC+01:00

1. Session date and time
New record default values were
New record Date and DateTime values before session change

I changed session date and time to the previous week
Change session date and time

New record default values stayed the same
New record Date and DateTime values after session date change

Select statements had the same values
TestDate
(VALIDFROM<={ts '2015-03-22 00:00:00.000'}) AND
(VALIDTO>={ts '2015-03-22 00:00:00.000'})
TestDateTime
(VALIDFROM<='2015-03-22T20:57:55') AND
(VALIDTO>='2015-03-23T20:57:55')

Conclusion 1: session date and time is not used by kernel for valid time state tables.

2. Client machine date and time
I opened client on machine2 and changed machine2 date to the previous week
Client machine date and time change

New record default values were based on machine2 date and time
New record Date and DateTime values after client machine date change

Select statements had the following values
TestDate
(VALIDFROM<={ts '2015-03-15 00:00:00.000'}) AND
(VALIDTO>={ts '2015-03-15 00:00:00.000'})
TestDateTime
(VALIDFROM<='2015-03-15T20:58:46') AND
(VALIDTO>='2015-03-15T20:58:46')

Conclusion 2: client machine date and time is used by kernel for valid time state tables.

3. User time zone
I changed user time zone to UTC+12:00
User time zone change

However client machine time zone was still UTC+01:00
Client machine time zone

It meant that it was Sunday 22.03.2015 on client machine, but in user time zone it was already Monday 23.03.2015
Time zone date and time examples

New record default values were:
New record Date and DateTime values after user time zone change

Select statements had the following values
TestDate
(VALIDFROM<={ts '2015-03-23 00:00:00.000'}) AND
(VALIDTO>={ts '2015-03-23 00:00:00.000'})
TestDateTime
(VALIDFROM<='2015-03-22T21:01:38') AND
(VALIDTO>='2015-03-22T21:01:38')


Conclusion 3: client machine date and time is converted into user time zone to get value for Date field. Client machine date and time is converted into UTC time zone to get value for UtcDateTime field.

Actually there are several examples in standard AX code, if you still have doubts:
Date field
\Data Dictionary\Tables\PayrollBenefitDetail\Methods\initValueFromHcmBenefit
this.ValidFrom = DateTimeUtil::date(
                     DateTimeUtil::applyTimeZoneOffset(_hcmBenefit.ValidFrom, 
                         DateTimeUtil::getOriginatingTimeZone(_hcmBenefit.ValidFrom)));

UtcDateTime field
\Data Dictionary\Tables\DirOrganizationName\Methods\updateName
utcdatetime     currentDateTime = DateTimeUtil::utcNow();

//Check if record updating is "current"
if (this.ValidFrom <= currentDateTime && this.ValidTo >= currentDateTime)
{
    ...
}

In standard AX in most cases systemDateGet() function is still used for Date field, sometimes - today() function. Only occasionally new and correct approach is used, which applies user time zone offset.
By the way systemDateGet() function was marked as depreciated in AX2009 and DateTimeUtil class was recommended to be used instead (msdn).

No comments:

Post a Comment