RE: [xsl] eXSLT date:add template

Subject: RE: [xsl] eXSLT date:add template
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Mon, 16 Jan 2006 11:31:40 -0000
The XPath 2.0 functions take the same view: 29 Feb plus one year is 28 Feb.

You can't avoid surprises with date arithmetic. It's not only leap years: 31
March plus 6 months minus 6 months is 30 March.

Michael Kay
http://www.saxonica.com/ 

> -----Original Message-----
> From: Fraser Goffin [mailto:goffinf@xxxxxxxxxxx] 
> Sent: 16 January 2006 10:58
> To: mail@xxxxxxxxxxxxxxxx
> Cc: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] eXSLT date:add template
> 
> I recently had a need to do some date calculations in XSLT 
> (1.0) and I 
> thought it would be a good opportunity to take a look at the 
> eXSLT function 
> and template library.
> 
> What I wanted to do was, given a start date (lets call it startDate), 
> calculate a new date (lets call it endDate) to be startDate + 
> 1 year - 1 
> day.
> 
> I settled on calling the date:add template twice, the first 
> time to add the 
> duration P1Y and the second time to subtract the day from the 
> result of the 
> first call (duration -P1D).
> 
> This works fine until we get to those pesky leap year dates 
> (and even for 
> these I'm not saying the implementation is wrong - I am just 
> looking for 
> clarification of the design). The date that I have a question 
> over is (not 
> surprisingly) the 29th February !. An example :-
> 
> Note: 2004 is a leap year.
> 
> The input doc looks like this :-
> 
> <eXLST_dateAdd_Test1>
>     <startDate>2004-02-29</startDate>
> </eXLST_dateAdd_Test1>
> 
> and the output like this :-
> 
> <eXLST_dateAdd_Test1>
>     <startDate>2004-02-29</startDate>
>     <currentDatePlus1Year>2005-02-28</currentDatePlus1Year>
>     <endDate>2005-02-27</endDate>
> </eXLST_dateAdd_Test1>
> 
> Here endDate is shown as the 27th Feb. One might expect this 
> to be the 28th, 
> but it all depends on whether adding 1 year to the 29th Feb 
> should be 28th 
> Feb in the following year or 01 March. The implementation 
> takes the position 
> that it should be 28th Feb and therefore, subtracting 1 day 
> yields 27th.
> 
> This seems reasonable.
> 
> BUT, if I use a startDate of 2004-2-28 I will also get the 
> same result. H'mm 
> now I'm not so sure, maybe adding 1 year to 29th February 
> SHOULD be 01 March 
> after all ??
> 
> Comments
> 
> Fraser.
> 
> Here's the simple XSLT I was using to test with :-
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="1.0" 
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
> xmlns:date="http://exslt.org/dates-and-times"; 
> extension-element-prefixes="date">
>     <xsl:import href="../functions/add/date.add.template.xsl"/>
>     <xsl:output method="xml" version="1.0" encoding="UTF-8" 
> indent="yes"/>
>     <xsl:template match="*|@*|text()">
>         <xsl:copy>
>             <xsl:apply-templates select="*|@*|text()|comment()"/>
>         </xsl:copy>
>     </xsl:template>
>     <xsl:template match="/">
>         <xsl:apply-templates/>
>     </xsl:template>
>     <xsl:template match="startDate">
>         <xsl:copy-of select="."/>
>             <!-- TASK: Add 1 Year minus 1 day -->
>             <!-- Add 1 Year -->
>             <xsl:variable name="currentDatePlus1Year">
>                 <xsl:call-template name="date:add">
>                     <xsl:with-param name="date-time" select="."/>
>                     <xsl:with-param name="duration" select="'P1Y'"/>
>                 </xsl:call-template>
>             </xsl:variable>
>            <currentDatePlus1Year><xsl:value-of 
> select="$currentDatePlus1Year"/></currentDatePlus1Year>
>             <!-- Subtract 1 Day -->
>             <xsl:variable name="endDate">
>                 <xsl:call-template name="date:add">
>                     <xsl:with-param name="date-time" 
> select="$currentDatePlus1Year"/>
>                     <xsl:with-param name="duration" select="'-P1D'"/>
>                 </xsl:call-template>
>             </xsl:variable>
>             <endDate>
>                 <xsl:value-of select="$endDate"/>
>             </endDate>
>     </xsl:template>
> </xsl:stylesheet>

Current Thread