Re: [xsl] Getting years from duration

Subject: Re: [xsl] Getting years from duration
From: Martin Holmes <mholmes@xxxxxxx>
Date: Fri, 7 Jun 2013 21:07:18 -0700
On 13-06-07 08:57 PM, Michael Sokolov wrote:
Yeah, that's a bit surprising.  But if you think about it there's a kind
of logic to it -- once you start working with dayTimeDuration, there
isn't any sensible way to know how many years that corresponded to
(because of leap years/seconds, and the Gregorian switch-over year and
so on), as you said yourself.

That's true, and it's interesting too. In one sense a duration abstracted from its start and end points loses some of its meaning.


This will do what you want I think:

let $d2 := year-from-date(xs:date("1674-11-08"))
let $d1 := year-from-date(xs:date("1600-12-09"))
return $d2 - $d1

If you're concerned about rounding (ie you think that 11 years 11 months
should be == 12 years), then you could add 6 months:

let $d2 := year-from-date(xs:date("1674-11-08") +
xs:yearMonthDuration("P6M"))
let $d1 := year-from-date(xs:date("1600-12-09"))
return $d2 - $d1

That works nicely. A function that would actually subtract the dates in a more methodical way -- subtracting days, "carrying" any overage to the months, then subtracting the months and carrying, then the years, could give a meaningful result in years, months and days, too. I'll hack that up tomorrow and see if it works. The day subtraction would have to be sensitive to month-length and leap-day.


Cheers,
Martin


-Mike


PS sorry for the XQuery instead of XSL, but the functions and datatypes
are the same...

On 6/7/2013 11:26 PM, Martin Holmes wrote:
We came up against what looked like a very simple XPath issue today,
and hit a brick wall with it. Given data that looks like this:

        <person role="author">
          <persName>Milton, John</persName>
          <birth when="1600-12-09"/>
          <death when="1674-11-08"/>
        </person>

we want to calculate the age of the person at death. So we thought:
subtract the death date from the birth date to get a duration, then
extract the years from the duration:

<xsl:template match="person">

    <xsl:variable name="life" select="xs:date(death/@when) -
xs:date(birth/@when)"/>

<xsl:variable name="age" select="years-from-duration($life)"/>

    <xsl:text>Age at death: </xsl:text>
    <xsl:value-of select="$age"/>

</xsl:template>


However, the only value we were able to get back, after trying all manner of permutations and casts, was zero. It appears that what comes back from the date subtraction (which I think uses the op:subtract-dates() operator) is always an xs:dayTimeDuration, and that cannot AFAIKS be manipulated into anything from which a year can be extracted.

It's always possible to get the number of days and divide by 365.25,
but it seems strange to have to do that. Given the range of date- and
duration-related functions, I'm sure there must be some better way of
getting the result. Does anyone know?

This is using Saxon 9.4.0.6.

Cheers,
Martin

Current Thread