- The Document Header
- CDA Entries
While CDA entries do include date and time, rendering them as part of the display of document sections is rarely done. The same techniques I mention for the header could also be applied to entries in the document sections though, if you happen to need something like that.
Date and Time values in the Header
There are numerous places within the document header where date and time could appear. Perhaps the most visible one is the /ClinicalDocument/effectiveTime element, which indicates when the document was created. Others include:
- author/time (the date and time the author wrote the document)
- legalAuthenticator/time (the date and time the document was legally signed)
- documentationOf/serviceEvent/effectiveTime (the date and time associated with the documented service)
- componentOf/encompassingEncounter/effectiveTime (the date and time associated with the encounter)
Time Zone or Locally Relevant Time?
Time zone is a function of politics, not math. When the author writes a document at 201408041452-0700, what is the time zone? Well, it depends upon where they are. They could be in California, in which case the time zone is PDT. But they could also be in Flagstaff, Arizona (where I will be next week for the HL7 Board Retreat), or in Zona Noroeste in the state of Baja California, in Mexico. Time zone then, is a function of where you are, not when you are, and even if you have the when, it doesn't narrow the where down sufficiently. A few years back, the US changed when it entered daylight savings time, so when you are, is also not just a function of time of day, but also of day, month and year. Give up yet? Good. Don't try to show the time zone in these cases. Just use the time offset.
Locally Relevant Time Zones
But people don't know what time 1200-0700 is, you say? OK, so what you need is to convert that to a locally relevant time in your stylesheet. So, how would you do that? I'm not going to go into a lot of detail here, but I will make some design recommendations:
- If possible, use XSLT 2.0 and the fn:adjust-dateTime-to-timeZone() function. In your transform. Get the locale from the user agent.
- If XSLT 2.0 is not available to you, try using EXSL date-time extensions with your XSLT processer.
Let's look at how you might do this with XSLT 2.0 first. You need to get the time zone from the browser. I'll assume you have a form somewhere, and that you submit that form at some point to the server. Here is how you might pass the time zone as offset in minutes from UTC (note that getTimezoneOffset() returns offset of UTC from the current time zone, and we want the inverse, the offset of the time zone from UTC, so we just negate it).
<input type='hidden' id='TZ' name='TZ' value=''/>
Date d = new Date();
document.getElementById('tz').value = -d.getTimezoneOffset();
On the server size, you'd simply pass TZ as a parameter to your transform (you ARE executing this CDA transform server side, aren't you? There are some very good reasons why you should do it that way).
In your stylesheet, you might do something like this to turn the offset in minutes into a time zone:
<xsl:if test='fn:number($TZ) < 0'>-</xsl:if>
<xsl:variable name='tzDuration' select='xs:dayTimeDuration($tzString)'/>
Then, when generating a time, you'd do something like this:
<xsl:with-param name='time' select='...'/>
Without XSLT 2.0
If you don't have an XSLT 2.0 parser, it gets a bit tricky. There are a couple of different ways to handle date/time formatting, but you really don't want to write any of that code yourself in XSLT. My favored way of handling it is by calling out to Java code to handle this sort of mess. You can use standard date/time functions in Java in this case. The java.text.SimpleDateFormat and java.util.GregorianCalendar classes provide just about everything you need to parse date/time values, and format them.
Below are a pair of templates using Java that are based on some work I used to convert CDA documents to XDS submission sets. With a little bit of tweaking, you could use this to format date time values however you wanted.
Take a V3 date/time stamp with or without milliseconds, and with or
without timezone specification and convert it to a date/time stamp in
the specified zone precise to seconds, or less
<xsl:param name="precision" select="14"/>
translate($time, '-', '+'),'+'), '+'))"/>
<xsl:if test="contains($time, '+') or contains($time, '-')">Z</xsl:if>
<xsl:variable name="parsedDate" select="java:parse($inputFormatter, $time)"/>
<xsl:with-param name="time" select="$parsedDate"/>
<xsl:with-param name="precision" select="$precision"/>
<xsl:with-param name="zone" select="$zone"/>
Take a Java Date and convert it to a date/time stamp in zone, precise
to seconds, or less
<xsl:param name="precision" select="14"/>
select="substring(java:format($outputFormatter, $time), 1, $precision)"/>
Of course, this assumes your platform is Java. What about all those .Net folk who are stuck with C#? The same principles apply, as C# has similar capabilities, I just don't know what they are ;-)
There is also a platform independent way to handle this, relying on EXSLT date and time extensions. But, as mentioned there, no XSLT processors support that natively. So you might just as well use a platform dependent implementation.