Question

Is there a function to calculate a duration from 2 dates within XSLT 2.0?

I'm trying to calculate the following from a Date Of Birth and Current Date:

  • Age in years
  • Age in months
Was it helpful?

Solution

I do not know of a predefined function in XSLT to accomplish this. But you can always write your own code. The solution below does not use a function, but you could easily rewrite it as a function.

The idea for the calculation is taken from here.

There are other (shorter) ways to to this, for a solution specific to XSLT 2.0 see Mads Hansen's answer here, for example. You'd have to slightly adapt the stylesheet you find there, though, since it outputs days.

Input

<root>
    <birth>1964-10-10</birth>
</root>

Stylesheet

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" />


<xsl:variable name="Birthday" select="//birth[1]"/>
<xsl:variable name="Age">
    <xsl:choose>
        <xsl:when test="month-from-date(current-date()) > month-from-date($Birthday) or month-from-date(current-date()) = month-from-date($Birthday) and day-from-date(current-date()) >= day-from-date($Birthday)">
            <xsl:value-of select="year-from-date(current-date()) - year-from-date($Birthday)" />
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="year-from-date(current-date()) - year-from-date($Birthday) - 1" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

<xsl:template match="/root">
    <result>
        <xsl:value-of select="$Age"/>
    </result>
</xsl:template>


</xsl:stylesheet>

Output

<?xml version="1.0" encoding="UTF-8"?><result>49</result>

OTHER TIPS

Age in months:

Note: This is an XSLT 1.0 solution; there is no real advantage to using XSLT 2.0 here (other than the convenience of having dedicated functions to extract the date components - which is fairly trivial anyway).

<xsl:template match="/">
    <age-in-months>
        <xsl:call-template name="age-in-months">
            <xsl:with-param name="date-of-birth" select="'2013-03-03'"/>
            <xsl:with-param name="current-date" select="'2014-03-02'"/>
        </xsl:call-template>
    </age-in-months>
</xsl:template>

<xsl:template name="age-in-months">
    <xsl:param name="date-of-birth" />
    <xsl:param name="current-date" />
    <xsl:param name="y1" select="substring($date-of-birth, 1, 4)"/>
    <xsl:param name="y2" select="substring($current-date, 1, 4)"/>
    <xsl:param name="m1" select="substring($date-of-birth, 6, 2)"/>
    <xsl:param name="m2" select="substring($current-date, 6, 2)"/>
    <xsl:param name="d1" select="substring($date-of-birth, 9, 2)"/>
    <xsl:param name="d2" select="substring($current-date, 9, 2)"/>
    <xsl:value-of select="12 * ($y2 - $y1) + $m2 - $m1 - ($d2 &lt; $d1)"/>
</xsl:template>

</xsl:stylesheet>

Added:

Note that age in years can be obtained as:

floor($age-in-months div 12)

so if you need it, the same template can provide both.

Is there a function to calculate a duration from 2 dates within XSLT 2.0?

Yes. Except that it's an operator, not a function. Just use the subtraction operator "-".

For example

current-date() - xs:date('1920-03-04')

gives my father's age in days:

P34332D

Getting his age in years and months is a bit more complicated, because of the complications of leap years (what do you do about people born on 29 February?). You can reduce this duration to a number of days by dividing by xs:dayTimeDuration('P1D'), and you can then get a reasonable approximation for the total number of years by dividing this by 365.25, but a more accurate calculation would probably be obtained by using year-from-date() on both dates, subtracting the results, and then subtracting one if the first date is later in the year than the second - which means basically writing the logic yourself.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top