I wrote a function to calculate someone's age from 2 dates (defined as the xs:date data type). I've tested it locally for various dates and ranges and it seems to be working properly. I'm sure I could make it more efficient and simplify it. I played with lots of the date functions, but with leap year involved, breaking down years, months and days seemed the be the only full proof method I could come up with. Anyone seem any flaws?
Code:
<xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fns="http://gai.com/xmlGroup/Functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="dates">
<Today>2050-01-15</Today>
<BirthDay>2025-01-15</BirthDay>
</xsl:variable>
<xsl:template match="/">
<xsl:value-of select="fns:getAge($dates/Today, $dates/BirthDay)"/>
</xsl:template>
<xsl:function name="fns:getAge">
<xsl:param name="CompareDate" as="xs:date"/>
<xsl:param name="BirthDate" as="xs:date"/>
<xsl:variable name="thisYear" select="number(substring(string($CompareDate),1,4))"/>
<xsl:variable name="thisMonth" select="number(substring(string($CompareDate),6,2))"/>
<xsl:variable name="thisDay" select="number(substring(string($CompareDate),9,2))"/>
<xsl:variable name="birthYear" select="number(substring(string($BirthDate),1,4))"/>
<xsl:variable name="birthMonth" select="number(substring(string($BirthDate),6,2))"/>
<xsl:variable name="birthDay" select="number(substring(string($BirthDate),9,2))"/>
<xsl:choose>
<!-- Error when the Birth Date is in the future -->
<xsl:when test="days-from-duration($CompareDate - $BirthDate) < 0">
<xsl:variable name="errorMsg">
<xsl:text>Invalid birth date. This person has not been born! Birth Date:</xsl:text>
<xsl:value-of select="$BirthDate"/>
<xsl:text>, Compare Date:</xsl:text>
<xsl:value-of select="$CompareDate"/>
</xsl:variable>
<xsl:value-of select="error((),$errorMsg)"/>
</xsl:when>
<xsl:otherwise>
<!-- Check Years -->
<!-- If years are equal; 0 years old -->
<xsl:choose>
<xsl:when test="$thisYear = $birthYear">
<xsl:value-of select="0"/>
</xsl:when>
<!-- Check Months -->
<!-- If current Month is after the Birth Month -->
<xsl:when test="$thisMonth > $birthMonth">
<xsl:value-of select="$thisYear - $birthYear"/>
</xsl:when>
<!-- If current Month is before the Birth Month; -1 year -->
<xsl:when test="$thisMonth < $birthMonth">
<xsl:value-of select="$thisYear - $birthYear - 1"/>
</xsl:when>
<!-- Check Days; Months must be equal -->
<!-- If current Day is after the Birth Day -->
<xsl:when test="$thisDay > $birthDay">
<xsl:value-of select="$thisYear - $birthYear"/>
</xsl:when>
<!-- If current Day is before the Birth Day; -1 year -->
<xsl:when test="$thisDay < $birthDay">
<xsl:value-of select="$thisYear - $birthYear - 1"/>
</xsl:when>
<!-- Months and Days must be equal; Happy Birthday! -->
<xsl:otherwise>
<xsl:value-of select="$thisYear - $birthYear"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>