Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old June 11th, 2010, 09:53 AM
Authorized User
 
Join Date: Apr 2008
Posts: 70
Thanks: 17
Thanked 1 Time in 1 Post
Send a message via Yahoo to iceandrews
Default Date Duration - Ignore Leap Year

I have a situation where I'd like to write a call template that takes 2 xs:date values as the input and returns the duration in days. This is very simple and I fully understand how to accomplish this. The problem I have is that I would like to IGNORE the extra day occurs in a leap year.

For example if I have 2 Dates such as follows:
Code:
<Dates>
   <BeginDate>2010-08-10</BeginDate>
   <EndDate>2013-08-10</EndDate>
</Dates>
Since 2012 is a leap year there's an extra day. So it returns from the day-from-duration() function. "1096". I would actually like "1095". Of course if it spans multiple leap years, I would want to remove all the extra leap year days from the result.

Currently I have a very simple call as follows:
Code:
<xsl:template name="getDuration">
     <xsl:param name="BeginDate" as="xs:date"/>
     <xsl:param name="EndDate" as="xs:date"/>

     <xsl:value-of select="days-from-duration($EndDate - $BeginDate)" />
</xsl:template>
I have some ideas about how to accomplish this, but they are all complicated. Perhaps setting up a table of leap years, check the start and end dates to see if they occur before or after Feb 28th of those leap years, and storing how many extra days are between them. Then I would just subtract that result from the days-from-duration() result.

Are there any simple methods that are part of XSLT/XPath that I can make use of to make this easier? I'm running Saxon 8.9 XSLT 2.0 compatible.

Thanks!
 
Old June 11th, 2010, 10:00 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

I think whether a year is a leap year can be computed, see http://www.xsltfunctions.com/xsl/fun...leap-year.html for an XSLT implementation, so you don't need to set up a table of leap years.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
The Following User Says Thank You to Martin Honnen For This Useful Post:
iceandrews (June 11th, 2010)
 
Old June 11th, 2010, 10:21 AM
Authorized User
 
Join Date: Apr 2008
Posts: 70
Thanks: 17
Thanked 1 Time in 1 Post
Send a message via Yahoo to iceandrews
Default

Excellent, thank you. So that eliminates one of the complications. I would still need to determine how many leap years are between the dates. And if the days fall inside or outside the set of leap years. (Before of after Feb 28th, etc).

Even with that function it can be complicated. If the starting and end are NOT leap years, there could be 4 in the middle. I'd have to increment or count the number of actual leap years between them.
 
Old June 11th, 2010, 10:33 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

An alternative would be to just calculate the number of days difference in the current year, then add 365 * number of years difference.

This would still have to take into account if the current year was a leap year and the two dates span the end of February.
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
The Following User Says Thank You to samjudson For This Useful Post:
iceandrews (June 11th, 2010)
 
Old June 11th, 2010, 10:39 AM
Authorized User
 
Join Date: Apr 2008
Posts: 70
Thanks: 17
Thanked 1 Time in 1 Post
Send a message via Yahoo to iceandrews
Default

Another good idea. Unfortunately the dates do not have to be exactly 1 year apart. Perhaps that was a bad example sample I provided. If could be 2010-05-21 to 2020-10-01, or even a very short duration like 2010-05-22.

But I think your idea has merit. I could take the Start and see if it's a leap year. Find the number of days left in the year. Take the end year, see if it's a leap year, and find the number days passed. Each duration here would be modified by +1/-1 if there's leap years involved. Then I could find the number of years between the dates and add 365 * number of years to the previous totals.

I think that might work! Let me me try!
 
Old June 11th, 2010, 03:02 PM
Authorized User
 
Join Date: Apr 2008
Posts: 70
Thanks: 17
Thanked 1 Time in 1 Post
Send a message via Yahoo to iceandrews
Default

Thank you for the great suggestion. I was able to write something that is functional. The logic you suggested was sound. It needs some optimization and re-coding to be a little more streamlined, but it's functional. I'll sit down with it again and really examine the ways to improve it a little later, but I wanted to share it with you guys. Thank you again.

Sample Input
Code:
<Dates>
    <TransactionEffectiveDate>2012-02-01</TransactionEffectiveDate>
    <ExpirationDate>2012-03-03</ExpirationDate>
</Dates>
XSLT Harness + Call Template
Code:
<xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fns="http://testuri.com/xmlGroup/Functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <Duration>
            <xsl:apply-templates select="Dates"/>
        </Duration>
    </xsl:template>

    <xsl:template match="Dates">
        <xsl:call-template name="getNomalizedDayDuration">
            <xsl:with-param name="StartDate" select="TransactionEffectiveDate"/>
            <xsl:with-param name="EndDate" select="ExpirationDate"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="getNomalizedDayDuration">
        <xsl:param name="StartDate" as="xs:date"/>
        <xsl:param name="EndDate" as="xs:date"/>

        <xsl:variable name="getStartDateDays">
            <xsl:variable name="StartYearMarch" select="xs:date(concat(year-from-date($StartDate),'-03-01'))"/>
            <xsl:variable name="EndStartYear" select="xs:date(concat((year-from-date($StartDate) + 1),'-01-01'))"/>
            <xsl:variable name="StartDateLeapYearFlag" select="fns:getLeapYearFlag($StartDate)"/>
            <xsl:variable name="setDaysBeforeMarch" select="days-from-duration($StartDate - $StartYearMarch)"/>
            <xsl:choose>
                <!-- Leap Year Day Case -->
                <xsl:when test="substring-after(string($StartDate),'-') = '02-29'">
                    <xsl:value-of select="days-from-duration($EndStartYear - $StartYearMarch)"/>
                </xsl:when>
                <!-- End Leap Year Case -->
                <xsl:when test="($setDaysBeforeMarch &gt;= 0) or (($setDaysBeforeMarch &lt; 0) and not($StartDateLeapYearFlag))">
                    <xsl:value-of select="days-from-duration($EndStartYear - $StartDate)"/>
                </xsl:when>
                <xsl:when test="(($setDaysBeforeMarch &lt; 0) and $StartDateLeapYearFlag)">
                    <xsl:value-of select="(days-from-duration($EndStartYear - $StartDate)) - 1"/>
                </xsl:when>
            </xsl:choose>
        </xsl:variable>

        <xsl:variable name="getEndDateDays">
            <xsl:variable name="EndYearFebruary" select="xs:date(concat(year-from-date($EndDate),'-02-28'))"/>
            <xsl:variable name="StartEndYear" select="xs:date(concat(year-from-date($EndDate),'-01-01'))"/>
            <xsl:variable name="EndDateLeapYearFlag" select="fns:getLeapYearFlag($EndDate)"/>
            <xsl:variable name="setDaysAfterFebruary" select="days-from-duration($EndYearFebruary - $EndDate)"/>
            <xsl:choose>
                <!-- Leap Year Case -->
                <xsl:when test="substring-after(string($EndDate),'-') = '02-29'">
                    <xsl:value-of select="days-from-duration($EndYearFebruary - $StartEndYear)" />
                </xsl:when>
                <!-- End Leap Year Case -->    
                <xsl:when test="($setDaysAfterFebruary &gt;= 0) or (($setDaysAfterFebruary &lt; 0) and not($EndDateLeapYearFlag))">
                    <xsl:value-of select="days-from-duration($EndDate - $StartEndYear)"/>                    
                </xsl:when>
                <xsl:when test="($setDaysAfterFebruary &lt; 0) and ($EndDateLeapYearFlag)">
                    <xsl:value-of select="(days-from-duration($EndDate - $StartEndYear)) - 1" />                    
                </xsl:when>
            </xsl:choose>
        </xsl:variable>

        <xsl:variable name="getNumberofYearDays" select="((year-from-date($EndDate) - year-from-date($StartDate)) - 1) * 365" />

        <NormalizedDays>
            <xsl:value-of select="$getStartDateDays + $getEndDateDays + $getNumberofYearDays" />
        </NormalizedDays>        
    </xsl:template>

    <xsl:function name="fns:getLeapYearFlag" as="xs:boolean" xmlns:fns="http://testuri.com/xmlGroup/Functions">
        <xsl:param name="date" as="xs:date"/>
        <xsl:sequence select="for $year in xs:integer(substring(string($date),1,4)) return($year mod 4 = 0 and $year mod 100 != 0) or $year mod 400 = 0"/>
    </xsl:function>
</xsl:stylesheet>





Similar Threads
Thread Thread Starter Forum Replies Last Post
year to date conversion rajesh_css Pro Java 1 November 11th, 2008 01:41 AM
Leap Year Calculation in SSRS anibis.knowledge BOOK: Professional SQL Server Reporting Services ISBN: 0-7645-6878-7 0 February 28th, 2008 07:39 AM
calculate date duration in asp.cet rjkulkarni2001 ASP.NET 2.0 Basics 2 January 13th, 2006 08:35 AM
date duration urgent rjkulkarni2001 ASP.NET 2.0 Professional 0 January 9th, 2006 06:11 AM
date duration in dotnet rjkulkarni2001 Classic ASP Basics 1 January 5th, 2006 07:06 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.