Recently, I was trying to change the display of some dates in our application. We’ve found that the simplest way for our international company to display dates is to stick to the dd-MMM-yyyy format since that seems the clearest. No one wonders whether 1/4/16 represent the 4th of January or the 1st of April, because they all see 04-Jan-2016.
This was simplest to fix for all the date fields that use simple inputText controls – just change the convertDateTime pattern.
<xp:inputText value="#{modDoc.RevPerf1Date}" id="revisedPerformanceDateStart"> <xp:dateTimeHelper></xp:dateTimeHelper> <xp:this.converter> <xp:convertDateTime pattern="dd-MMM-yyyy"></xp:convertDateTime> </xp:this.converter> </xp:inputText>
Then, I noticed that in place I wasn’t letting them edit the dates, it wasn’t using that format. We’re not displaying the inputText, but using a label computed from that control to determine what to display. This code may actually hurt your eyes, but it did convert the date into a US-format date, like 01/04/2016.
<xp:label id="label14" style="color:black;"> <xp:this.value><![CDATA[#{javascript:if(modDoc.isNewNote()){ if(modDoc.getItemValueDate("PerfDate1") != null) { var termBegin = @Text(modDoc.getItemValue("PerfDate1")); if(termBegin != ""){ var dt2:NotesDateTime = session.createDateTime(termBegin); var d = new Date(dt2.toJavaDate()); var mon = ("0" + (d.getMonth() + 1)).slice(-2) var td = ("0" + d.getDate()).slice(-2); var yr = d.getFullYear(); mon + "/" + td + "/" + yr } } else { if(sessionScope.POPerformBeginDate != null && sessionScope.POPerformBeginDate != "null" && sessionScope.POPerformBeginDate != ""){ var dt:NotesDateTime = session.createDateTime(sessionScope.POPerformBeginDate); dt.toJavaDate() modDoc.setValue("PerfDate1",dt); var d = new Date(dt.toJavaDate()); var mon = ("0" + (d.getMonth() + 1)).slice(-2) var td = ("0" + d.getDate()).slice(-2); var yr = d.getFullYear(); mon + "/" + td + "/" + yr } } } else { var termBegin = @Text(modDoc.getItemValue("PerfDate1")); if(termBegin != ""){ var dt2:NotesDateTime = session.createDateTime(termBegin); var d = new Date(dt2.toJavaDate()); var mon = ("0" + (d.getMonth() + 1)).slice(-2) var td = ("0" + d.getDate()).slice(-2); var yr = d.getFullYear(); mon + "/" + td + "/" + yr; } }}]]></xp:this.value> </xp:label>
Before we decided to convert to the new format, the ugliness of the code didn’t matter. It was used in one place (printing purchase order modifications) and it worked. Since I didn’t want to invent my own library function for computing the text value of the date in the new format, I searched for a better way to format the dates. I ran across Declan Lynch’s blog entry on using SimpleDateFormat. Unfortunately, that just points in the right direction, rather than providing working code. So, when I tried to implement that for displaying the labels correctly, I just couldn’t get it to work. This frustration led me to the simple solution: use convertDateTime on the labels. Duh!
<xp:label id="performanceDateStartDisplay" style="color:black;"> <xp:this.value><![CDATA[#{javascript:getComponent("performanceDateStart").getValue();}]]></xp:this.value> <xp:this.converter> <xp:convertDateTime pattern="dd-MMM-yyyy"></xp:convertDateTime> </xp:this.converter> </xp:label>
Now, on the printed purchase order modification, I also had changes in dates detailed in the text as a sentence. So, you’d see To Change the Period of performance from 01/04/2016 to 01/08/2106 to 01/11/2016 to 01/15/2016, which was not using our newly minted date format. I couldn’t figure out a way to use the converters within the text without creating several computed labels (each with a rendered formula) to display the text. Then, I remembered my dalliance with SimpleDateFormatter.
So, within that control, I brought in the package and created a function that gets the field value as a Vector using getItemValueDateTimeArray and formats it using my chosen SimpleDateFormat. The text string gets built with four calls to that function and returns our text To Change the Period of performance from 04-Jan-2016 to 08-Jan-2016 to 11-Jan-2016 to 15-Jan-2016
<xp:text id="revisedPerformanceRange"> <xp:this.value><![CDATA[#{javascript:function getFormattedDate ( doc:NotesDocument, fieldName:String ) { importPackage(java.text); var dateFormatter:java.text.SimpleDateFormat = new SimpleDateFormat("dd-MMM-yyyy"); var d:Date = new Date(@Today()); if ( doc.hasItem (fieldName) ) { var valueVector:java.util.Vector = doc.getItemValueDateTimeArray(fieldName); var iterator = valueVector.iterator(); while (iterator.hasNext()) { var itemvalue = iterator.next(); if ((typeof(itemvalue)).endsWith("DateTime")) { d = new Date(itemvalue.toJavaDate()); return dateFormatter.format(d); } } } else { return fieldName + " is not on the document" } } var modNotesDoc:NotesDocument = modDoc.getDocument(); var revisedPerformanceRangeText = "To Change the Period of performance from "; revisedPerformanceRangeText = revisedPerformanceRangeText + getFormattedDate(modNotesDoc,"PerfDate1") + " to "; revisedPerformanceRangeText = revisedPerformanceRangeText + getFormattedDate(modNotesDoc,"PerfDate2") + " to "; revisedPerformanceRangeText = revisedPerformanceRangeText + getFormattedDate(modNotesDoc,"RevPerf1Date") + " to "; revisedPerformanceRangeText = revisedPerformanceRangeText + getFormattedDate(modNotesDoc,"RevPerf2Date"); return revisedPerformanceRangeText;}]]></xp:this.value> </xp:text>
Took some fiddling to figure it out, but gave me exactly what I wanted, two different ways.
The only issue I see is that month names may not be as universal as you think. For example, the Italian word for June is giugno.
What works for us is YYYY/MM/DD. People on seem to grasp that if the date starts with the year, month is going to be next. YMMV.
While you’re correct that the month name isn’t the same in every language, our application is entirely in English. So, seeing a date represented only by numbers will confuse many people, they are used to the month names being in English and won’t be confused. I do wonder if the MMM will pick up the month names from the user’s language if it’s set on their machine. When I proposed YYYY/MM/DD, it was shot down. “No one uses that except IT people,” I was told. So, because of our particular situation (English language app, but deployed internationally, with a rejection of the descending format) this solution will be best for us. That said, the same code could be used with the different value for the SimpleDateFormat.