How to Manage Dates in Automation Chains


Thu 13 March 2014 By Laurent Doguin

Calendar
Here's a question I actually ask myself quite often. Managing dates with Studio is not particularly intuitive. Part of the reason is that, to make things simple, you don't always manipulate the same objects in the same context. The other part is that the Date APIs in Java are simply not easy to use. To learn more about this, you really have to read the documentation Bertrand wrote about expression and scripting language.

This post is focused on Date handling in automation chains. When you're building an automation chain, the scripting language used is MVEL. When writing MVEL script, you have access to most of the regular Java Objects. Take a look at the Type Literals documentation for more details. The next step to better understand dates in automation chains is to know which kind of Java objects you're dealing with. Every date retrieved from a document property will be represented as a GregorianCalendar.

Assign a Date from a Document Property


So what can you do with dates? One thing to do easily is set up an expire date 10 days following the creation date of the document. My first naive implementation looked like this:

Fetch > Context Document(s)
Document > Update Property
value: @{Document["dc:created"].add(java.util.Calendar.DAY_OF_MONTH, 10)}
xpath: dc:expired
save: true

This automation chain runs at the creation of a document. What's going to happen is that the dc:expired will be null and 10 days will be added to the creation date. This is far from what I wanted to achieve :-)

The dc:expired property is null because the add method return nothing, which means that the value field will be 'nothing'. And the dc:created property is incremented because that's exactly what @{Document["dc:created"].add(5,10)} does. Here the property dc:created is directly modified.

So let's fix this with the clone method. Cloning Document["dc:created"] creates a new object. This way if you modify the clone version it obviously won't modify the original object.

Fetch > Context Document(s)
Scripting > Run Script
script:
Context["expirationDate"]=Document["dc:created"].clone();
Context["expirationDate"].add(java.util.Calendar.DAY_OF_MONTH, 10);
Document > Update Property
value: @{Context["expirationDate"]}
xpath: dc:expired
save: true

Format a Date as a String


Another common thing to do is take a date and format it as a nice String. Usually in Java you would use the SimpleDateFormat class. It's format method takes a Date object as parameter. To get a Date object from a Calendar Date, you can call the getTime method. To set an existing date as a string in the context, the automation chain would look like this:

Fetch > Context Document(s)
Execution Context > Set Context Variable
name: MyVariableName
value: @{new java.text.SimpleDateFormat("MM-dd-yyyy").format(Document["dc:created"].getTime())}

Here I assign to the context variable MyVariableName the creation date formated like 01-20-2014.

The CurrentDate Object


When you use the CurrentDate object in an Automation Chain, you're actually using another Java Object called DateWrapper. Its goal is to ease the use of dates in MVEL. You can also get a DateWrapper using the provided functions in the scripting assistant:

wrappedDate = @{Fn.date(Document["dc:created"].getTime())}
wrappedDate = @{Fn.calendar(Document["dc:created"])}

Once you have a DateWrapper object, it's really easy to get the different part of a date (Day, Hour, Minute, Month, Second, Week, Year, Time etc...), to format the date as a String, to add a number of seconds, minutes, hours, days, week, months or years to the date or to convert it to a Timestamp usable in an NXQL query.

If we take the expire date example from before, adding the 10 days is easier, more readable:

Fetch > Context Document(s)
Scripting > Run Script
script:
wrappedDate = Fn.calendar(Document["dc:created"]).days(10);
Context["expirationDate"]= wrappedDate.getCalendar();
Document > Update Property
value: @{Context["expirationDate"]}
xpath: dc:expired
save: true

You don't have to call the clone method as it's pretty much what happens when the DateWrapper object is created. You still have to call the getCalendar method to retrieve the GregorianCalendar instance we need to set the property. In the future we'll try to make this automatic so it becomes even easier.

In the same idea, the text formatting becomes simpler. Just compare this:

@{new java.text.SimpleDateFormat("MM-dd-yyyy").format(Document["dc:created"].getTime())}

to this:
@{Fn.calendar(Document["dc:created"]).format("MM-dd-yyyy")}

Let me know in the comments if you have any questions, or if you want to see more posts like this.


Category: Product & Development
Tagged: How to, Nuxeo Automation