Time functions in XSLT 2
This aricle describes the basic time and date functions in XSLT 2.0. It only touches the surface of the functionality provided using a series of examples.
XSLT 2.0 added alot of functionality, but the biggest difference from XSLT 1.0 is typing. This means that the XSLT engine knows the difference between strings, numbers and dates. In this article I will illustrate the use of date and time functions to do alot of things that was nearly impossible with XSLT 1.0. All the illustrated functionality can be used in Vertical Site 4.1 and later.
Current time
We start off by simply getting hold of the current time and date. XSLT 2.0 define some functions for this (Actually, all functions that we use here is defined in the XPath 2.0 specification):
- current-date() - returns the current date (not time)
- current-time() - returns the current time (not date)
- current-dateTime() - returns both current date and time
To use the functions we must ensure that we are using the right XSLT version by defining it into the version field. So, the example below uses all three functions:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<values>
<date>
<xsl:value-of select="current-date()"/>
</date>
<time>
<xsl:value-of select="current-time()"/>
</time>
<dateTime>
<xsl:value-of select="current-dateTime()"/>
</dateTime>
</values>
</xsl:template>
</xsl:stylesheet>
When executing this, you would get the following result:
<?xml version="1.0" encoding="UTF-8"?> <values> <date>2008-10-08+02:00</date> <time>10:22:21.53+02:00</time> <dateTime>2008-10-08T10:22:21.53+02:00</dateTime> </values>
Extracting components
Since the XSLT engine knows the date types we can extract the year, month, day and timezone from the date. To do this we have the following functions:
- day-from-date(..) - extracts the day from a date (ex: 13)
- month-from-date(..) - extracts the month from a date (ex: 12)
- year-from-date(..) - extracts the year from a date (ex: 2008)
- timezone-from-date(..) - extracts the timezone from a date (ex: PT1H)
To extract components from time, we have the following functions avaliable:
- hours-from-time(..) - extracts the hours from time (ex: 14)
- minutes-from-time(..) - extracts the minutes from time (ex: 13)
- seconds-from-time(..) - extracts the seconds (and milliseconds) from time (ex: 11.43)
- timezone-from-time(..) - extracts the timezone from a time (ex: PT1H)
So, as you can see it follows a pattern in the function names. The next function group extracts data from dateTime datatype and follows the same pattern as above:
- day-from-dateTime(..)
- month-from-dateTime(..)
- year-from-dateTime(..)
- hours-from-dateTime(..)
- minutes-from-dateTime(..)
- seconds-from-dateTime(..)
- timezone-from-dateTime(..)
Here is a simple example to illustrate the usage:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="date" select="current-date()"/>
<xsl:variable name="time" select="current-time()"/>
<xsl:variable name="dateTime" select="current-dateTime()"/>
<values>
<day>
<xsl:value-of select="day-from-date($date)"/>
</day>
<hours>
<xsl:value-of select="hours-from-time($time)"/>
</hours>
<seconds>
<xsl:value-of select="seconds-from-dateTime($dateTime)"/>
</seconds>
</values>
</xsl:template>
</xsl:stylesheet>
This gives the following output:
<?xml version="1.0" encoding="UTF-8"?> <values> <day>8</day> <hours>10</hours> <seconds>7.616</seconds> </values>
Typecasting
Sometimes it is necessary to convert values. The most common case is to convert strings to date/time values so that we can manipulate the data as real date/time types. To do this we need to do typecasting. This is best illustrated by an example:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="time" select="'12:12:12' cast as xs:time"/>
<xsl:variable name="date" select="'2008-12-12' cast as xs:date"/>
<xsl:variable name="dateTime" select="'2008-12-12T12:12:12' cast as xs:dateTime"/>
<values>
<hours>
<xsl:value-of select="hours-from-time($time)"/>
</hours>
<year>
<xsl:value-of select="year-from-date($date)"/>
</year>
<day>
<xsl:value-of select="day-from-dateTime($dateTime)"/>
</day>
</values>
</xsl:template>
</xsl:stylesheet>
When executing this, we get the following output:
<?xml version="1.0" encoding="UTF-8"?> <values> <hours>12</hours> <year>2008</year> <days>12</days> </values>
Another (more simpler) way to do the above is to use the constructors that is avaliable. All types has a default constructor that takes a string value. So, when we execute xs:date($str) we would get the data as date, not string. The following example does the same thing as the previous code:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="time" select="xs:time('12:12:12')"/>
<xsl:variable name="date" select="xs:date('2008-12-12')"/>
<xsl:variable name="dateTime" select="xs:dateTime('2008-12-12T12:12:12')"/>
<values>
<hours>
<xsl:value-of select="hours-from-time($time)"/>
</hours>
<year>
<xsl:value-of select="year-from-date($date)"/>
</year>
<day>
<xsl:value-of select="day-from-dateTime($dateTime)"/>
</day>
</values>
</xsl:template>
</xsl:stylesheet>
Durations
Durations are value types that can be added or substracted from all the date/time types. Using durations can simplify date/time calculations a great deal, but it requires an understanding of the duration pattern. This pattern is described in the XPath 2.0 functions and operator documentation and will not be described in detail here.
So, the easiest way to understand duration is to look at an example:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="date" select="xs:date('2001-01-01')"/>
<xsl:variable name="time" select="xs:time('11:00:00')"/>
<values>
<dateAdd>
<xsl:value-of select="$date + xs:yearMonthDuration('P2Y2M')"/>
</dateAdd>
<dateSub>
<xsl:value-of select="$date - xs:yearMonthDuration('P1M')"/>
</dateSub>
<timeAdd>
<xsl:value-of select="$time + xs:dayTimeDuration('P0DT3H15M')"/>
</timeAdd>
<timeSub>
<xsl:value-of select="$time - xs:dayTimeDuration('P0DT1H30M')"/>
</timeSub>
</values>
</xsl:template>
</xsl:stylesheet>
This gives the output:
<?xml version="1.0" encoding="UTF-8"?> <values> <dateAdd>2003-03-01</dateAdd> <dateSub>2000-12-01</dateSub> <timeAdd>14:15:00</timeAdd> <timeSub>09:30:00</timeSub> </values>




Comments
10 October 2008 09:14
Commented by Per Allan Johansson
A little pretty-print example also. If you use a typical Vertical Site contenttype with a date field it will return a date like this: 2008-10-10. If you want to write this in a norwegian manner: 10.10.2008, the easiest way is like this: <xsl:value-of select="replace($myDate, '(\d+)-(\d+)-(\d+)','$3.$2.$1'))"/>
10 October 2008 09:14
Commented by Per Allan Johansson
>xsl:value-of select="replace(startdate,'(\d+)-(\d+)-(\d+)','$3.$2.$1')"/<
24 February 2009 09:40
Commented by Lars Eirik Rønning
Great article!
If you want to comment on this article you need to be logged in.