Search This Blog

Thursday, 9 May 2013

Date handling in Livecycle Designer ES forms

Problem

The internal format of a DateTimeField is yyyy-mm-dd or yyyy-mm-ddThh:mm:ss. These are sensible formats but formats that the standard JavaScript Date object does not handle in its constructor nor does it have methods to display a date into these formats. There are also several common date operations that are not handled by the JavaScript Date object, methods like addWeeks, getWeekOfYear, getAge, etc.

Solution

This sample shows how to extend the standard JavaScript object and add handling for new date formats in the constructor as well as add new methods to format dates, perform date arithmetic, and return additional information about a date. All the normal JavaScript Date object methods are still available and the object can still be used were a JavaScript Date object can be used like the util.scand function.

Detailed explanation

The constructor function of this new object can take a string with a date in the yyyy-mm-dd or yyyy-mm-ddThh:mm:ss formats or just take a DateTimeField object itself.

So to test for a valid date in the exit event you can use the following code;

if (isNaN(XFADate.newDate(this)))
{
    // handle invalid date
}

Using isNaN (is not a number) is a standard way of testing if a JavaScript Date object has a valid date value.
Below is a screen shot of the sample form using the XFADate script object;


Other things to note about Date handling in forms.


Selecting a date with the date picker


One of the nice things about the standard date picker popup that might not be widely known,  the first date picker gives you a month view, click the heading "April 2012" (in this sample) and you get a year view, click the year and you get a decade view and finally click the decade header and you get a century view.


Entering yyyy-mm-dd format dates


One of the not so great features of the DateTimeField is that it will always allows the user to type a date in the yyyy-mm-dd format, regardless of the display or edit formats.  This has not been a problem for me, but the user can also type yyyy-mm and the DateTimeField will default to the 1st of the month, even though the rawValue will retain the yyyy-mm format.  To some this will be a handy short cut but to others will cause confusion.

To make sure the displayed value of a DateTimeField matches the rawValue when the date value has a yyyy-mm format in the exit event I have the following code to update the display and edit formats;

if (isNaN(XFADate.newDate(this)))
{
    this.format.picture.value = "date{'"+this.rawValue+"'}";
    this.ui.picture.value = "date{'"+this.rawValue+"'}";
}

To make this work I need to save the specified display and edit formats in the initialize event by adding nodes under the field's desc element;

this.desc.nodes.append(xfa.form.createNode("text", "displayFormat"));
this.desc.nodes.namedItem("displayFormat").value = this.format.picture.value;
this.desc.nodes.append(xfa.form.createNode("text", "editFormat"));
this.desc.nodes.namedItem("editFormat").value = this.ui.picture.value;


In the enter event I set the display and edit formats to their defaults (if these are invalid then the calendar picker will not open).

this.format.picture.value = this.desc.nodes.namedItem("displayFormat").value;
this.ui.picture.value = this.desc.nodes.namedItem("editFormat").value;


util.scand


Another quirk of date handling in the Acrobat API is the util.scand method, this allows a string to be parsed into a date, like util.scand("yyyy-mm-dd", "2012-04-02"). The problem that occurs is the Date object returned will have a random amount of milliseconds set.  This generally isn't a problem but if you are comparing dates a few milliseconds can make a big difference.  The second page of the sample form demonstrates this problem.  The XFADate script object resolves this problem by using a regex to parse the date string.

This function also has the same problem as the DateFileField when handling dates without a day, so util.scand("yyyy-mm-dd", "2012-04") will return a JavaScript Date object with a value of 2012-04-01.

Also, if a null value is passed into util.scand then then a Date object with the value set to the current date will be returned.  This can easily become a problem with a call like util.scand("yyyy-mm-dd", Date1.rawValue), if Date1.rawValue is null then the current date is returned.

Download the XFADateForm.pdf or the script object fragment XFADate.xdp.


3 comments:

  1. Hi Bruce,
    I am using your xfa date object to be able to return the easter sunday date of a random year and I've found out that if we enter a date before the year 1900 it will say that the date is an invalid date... I am looking at your code and the problem seems to be in the function toXFADate();
    The error occurs on the util.printd() function...
    Are you aware of this issue? is it possible to have it fix?!?

    ReplyDelete
  2. Hi Robert

    I haven't had the need to use dates prior to 1900 so hadn't come across this problem.

    It seems to be a problem using util.printd() and using the XFA picture clauses, that is when the third parameter is true.

    You could try changing the line;

    return isNaN(this) ? "Invalid Date" : util.printd("YYYY-MM-DD", this, true)

    to

    return isNaN(this) ? "Invalid Date" : util.printd('yyyy-mm-dd', this)

    This is using the Acrobat JavaScript date picture format, which I had wanted to avoid as it's just another thing to learn.

    There are other places in my code that will probably cause the same exception, but the XFA picture formats are also more functional, so the fixes might not be so simple. Hopefully you wont need those functions.

    Regards

    Bruce

    ReplyDelete