xsl-list
[Top] [All Lists]

RE: Date Difference

2005-12-19 17:15:29
-----Original Message-----
From: Wendell Piez

If you want your dates to have "dateness", XPath 2.0 is the way to 
go, and Mike H has shown the way forward.

As much as to say "over yonder".  Wendell reminds me that I failed to
account for single digit days, as well.  It matters because the cast to
xs:date demands a normalized, standardized and reliable lexical form:

YYYY-MM-DD

FWIW, the following stylesheet, much revised, does just what is required and
nothing more, over the following instance XML:

testDate2.xml
-------------

<?xml version="1.0"?>
<data>
<dateRange>
<date>9/1/2004</date>
<date>10/25/2005</date>
</dateRange>
</data>


testDate2.xsl
-------------

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xs="http://www.w3.org/2001/XMLSchema";
  xmlns:fn="http://www.w3.org/2005/xpath-functions";
  version="2.0"
  exclude-result-prefixes="xs fn">

  <xsl:template match="/">
    <output>
      <xsl:apply-templates/>
    </output>
  </xsl:template>

  <xsl:template match="*/dateRange">

    <xsl:variable name="dateOne">
      <xsl:call-template name="correctDate">
        <xsl:with-param name="dateParts" 
                        select="fn:tokenize(date[1], '/')"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="dateTwo">
      <xsl:call-template name="correctDate">
        <xsl:with-param name="dateParts" 
                        select="fn:tokenize(date[2], '/')"/>
      </xsl:call-template>
    </xsl:variable>

    <duration>
      <xsl:value-of select="xs:date($dateOne) - xs:date($dateTwo)"/>
    </duration>

  </xsl:template>

  <xsl:template name="correctDate">
    <xsl:param name="dateParts"/>
    <xsl:value-of select="$dateParts[3]"/>
    <xsl:text>-</xsl:text>
    <xsl:call-template name="pad">
      <xsl:with-param name="digits" select="$dateParts[1]"/>
    </xsl:call-template>
    <xsl:text>-</xsl:text>
    <xsl:call-template name="pad">
      <xsl:with-param name="digits" select="$dateParts[2]"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="pad">
    <xsl:param name="digits"/>
    <xsl:choose>
      <xsl:when test="fn:string-length($digits) = 1">
        <xsl:value-of select="concat('0', $digits)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$digits"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>


Producing this output with Saxon 8:

<?xml version="1.0" encoding="UTF-8"?>
<output>
<duration>-P419D</duration>
</output>


I have broken out two parameterized templates: one to correct a supplied
date in 'Merkin grade-school form to ISO form and another pre-padding a zero
to any supplied string if a single digit.

All very instructive.  The machines are simple and have correspondingly
strict lexical requirements.  fn:replace() no longer made sense when each
token of the string needed touched.  And fn:tokenize() is slick as snot.

The result carries a leading minus when the first supplied date temporally
precedes the second.


Mike

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



<Prev in Thread] Current Thread [Next in Thread>