Nobody likes an awkward date. But they happen and hopefully this post will help break the ice. Puns aside, handling dates in Adobe Experience Manager can be tricky, and in this post, I’ll show you one of the many ways you can handle dates in AEM.
The Problem
Typically, you’d use the Date field to give authors the ability to add a date in a component dialog. Take this dialog for example:
and assume the start date field looks like this:
<event-start-date jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/datepicker" fieldLabel="Event Start Date" name="./eventStartDate" required="{Boolean}true"/>
Upon selecting a date, say 2018-10-18, and submitting; the value stored in the JCR will be of type “Date” and the value might look like this:
2018-10-18T00:00:00.000-05:00
The problem here is that the date submitted includes the author’s local timezone (specifically computer timezone).
If I changed my computer’s time zone to India, for example, then submitted the same value, I’d get a different date:
2018-10-18T00:00:00.000+05:30
Timezones are denoted here with an offset from the UTC time. See a full list on wikipedia
The first date is UTC-05:00 and the second is UTC+5:30
This means that if you have distributed authors, the dates will differ. This is especially problematic if, for example, your author is in India and your AEM server is located east coast United States.
Now, there are many ways to handle this, depending on your situation. You could:
- Assume one time zone and do server-side conversions to that time zone always.
- Convert dates via Javascript on the client-side to display the time relative to the user’s current time (or any other time).
One Possible Solution
In my case, I just needed a simple Year/Month/Day format that does not change and the location is always the US. The simplest solution is to save the Date as a “String” to the JCR and not Date then display it as is, or parse it (known fixed format) and use it elsewhere. But, the DatePicker does not give you that option. Sure, it allows you to format the value using a pattern, but the JCR type still remains as Date and is still saved in the same format, see: DatePicker docs.
Using @TypeHint
You might have seen @TypeHint before while inspecting AEM dialogs. You can see the docs for it here. TypeHint is a way to tell sling the JCR property type I want to save a property as. See the docs for examples.
Back to my problem, I want to save that “eventStartDate” field as a “String.” This can be achieved by adding an additional hidden field to my dialog that has the same name value “eventStartDate” plus “@TypeHint” to indicates that it is a type hint field. Also, set the “value” property to “String” because that’s the type I want to save it as.
<make-startDate-string about="This causes eventStartDate to be saved as a String in JCR instead of Date" jcr:primaryType="nt:unstructured" sling:resourceType="/libs/granite/ui/components/coral/foundation/form/hidden" name="./eventStartDate@TypeHint" value="String"/> <event-start-date jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/datepicker" fieldLabel="Event Start Date" name="./eventStartDate" required="{Boolean}true" valueFormat="YYYY/MM/DD"/>
So now when I submit my dialog, the value saved is always a String with the specified format “YYYY/MM/DD”.
For example, selecting the date: “2018/10/18” actually saves “2018/10/18” to the JCR. Problem Solved. Now I can just display that string as is or parse it for further processing!
Special thanks to Dan Klco for suggesting the solution.