0

I have 2 dates. Difference between them - 2 Bussines days. How to create code on XSLT in ver 3.0 TO calculate only business days (i.e excluding Saturday and Sunday )?

<date1>2023-03-10</date1>
<date2>2023-03-14</date2>

I have found this code. But its only working at xslt ver.1.0 How to get only business days between two dates in xslt 1.0

And I would like to use XPATH to determine those dates in code. Because the dates can change, my task is for me to also pull the dates using Xpath

Iamfitz
  • 19
  • 7
  • Why does the XSLT 1 (and https://stackoverflow.com/a/65877187/252228 seems to have an XSLT 2 solution as well) from the question you linked to not work with your XSLT 3 processor? – Martin Honnen Mar 14 '23 at 07:34
  • @MartinHonnen according that approach = my result is 4 days. but need 2 Bussines day. I mean this is not working at XSLT 3( – Iamfitz Mar 14 '23 at 07:40
  • Anything that works in XSLT 1.0 will work in XSLT 3.0 as well. The XSLT 1.0 solution I posted in the linked question will return the expected result of 2 in your example. To get the dates from your input XML, simply point the `xsl:with-param` instructions to the relevant nodes in the XML. – michael.hor257k Mar 14 '23 at 07:56
  • Why 2? Isn't Friday, the 10th of March a business day, as Monday, the 13th, as Tuesday, the 14th? – Martin Honnen Mar 14 '23 at 07:59
  • Friday - 2023-03-10 Tuesday -2023-03-14. Difference 4 Calendar Days. But If we use 2 BD to calculate the difference. There difference 2 bussines days! – Iamfitz Mar 14 '23 at 08:15
  • @MartinHonnen It's a matter of convention: between today (Tuesday) and tomorrow (Wednesday) only 1 business day elapsed. If you count both days, then you will arrive at a 1 day difference between today and today. – michael.hor257k Mar 14 '23 at 08:25
  • @michael.hor257k nope. In my case( I can't receive correct dates) I also have issues line The operator '-' is not defined for operands of type xs:integer and xs:string... anyway look like that code realy don't works at xslt 3.0 – Iamfitz Mar 14 '23 at 08:28
  • 1
    @Iamfitz You're right, it requires backwards compatibility mode. I will try to post an XSLT 2.0/3.0 solution later today. – michael.hor257k Mar 14 '23 at 08:42
  • @michael.hor257k Thank you so much! It's really work. Can you please assist with using XPath's insted of variables for extracting dates values. I mean I want to use this XPath somewhere in template. /input/range/start_date /input/range/end_date Is it possible to change xslt by using XPath? Where I should add it? – Iamfitz Mar 15 '23 at 11:40
  • 1
    In my example, the context is already `range`. From this context, the expression `` selects the the current range's `start_date` and `end_date `. You haven't posted a [mcve] so I don't know how exactly you need to adjust this. – michael.hor257k Mar 15 '23 at 12:54
  • @michael.hor257k can you please look at this one ? thanks! https://stackoverflow.com/questions/75745415/how-to-create-code-on-xslt-in-ver-3-0-to-calculate-only-business-days-i-e-exclu – Iamfitz Mar 15 '23 at 13:32

1 Answers1

1

Here is one way you could look at it. Note that this assumes that the two given dates will not fall on Saturday or Sunday.

XML

<input>
    <range>
        <start_date>2023-03-10</start_date>
        <end_date>2023-03-14</end_date>
    </range>
    <range>
        <start_date>2023-03-10</start_date>
        <end_date>2023-03-15</end_date>
    </range>
    <range>
        <start_date>2023-03-10</start_date>
        <end_date>2023-03-16</end_date>
    </range>
    <range>
        <start_date>2023-03-10</start_date>
        <end_date>2023-03-17</end_date>
    </range>
    <range>
        <start_date>2023-03-10</start_date>
        <end_date>2023-03-20</end_date>
    </range>
</input>

XSLT 2.0

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://www.example.com/my"
exclude-result-prefixes="xs my">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:function name="my:abs-week-number">
    <!-- weeks start on Sunday -->
    <xsl:param name="date" as="xs:date"/>
    <xsl:variable name="rataDie" select="days-from-duration($date - xs:date('0001-01-01')) + 1"/>
    <xsl:sequence select="$rataDie idiv 7"/>
</xsl:function>

<xsl:function name="my:workdays-in-range">
    <xsl:param name="startDate" as="xs:date"/>
    <xsl:param name="endDate" as="xs:date"/>
    <!-- total days -->
    <xsl:variable name="total-days" select="days-from-duration($endDate - $startDate)"/>
    <!-- number of week boundaries (Sat|Sun) in range -->
    <xsl:variable name="weekends" select="my:abs-week-number($endDate) - my:abs-week-number($startDate)"/>
    <!-- total days minus weekend days -->
    <xsl:sequence select="$total-days - 2*$weekends" />
</xsl:function>

<xsl:template match="/input">
   <output>
        <xsl:for-each select="range">
            <workdays start-date="{start_date}" end-date="{end_date}">
                <xsl:value-of select="my:workdays-in-range(start_date, end_date)"/>
            </workdays>
        </xsl:for-each>
    </output>
</xsl:template> 

</xsl:stylesheet>

Result

<?xml version="1.0" encoding="utf-8"?>
<output>
   <workdays start-date="2023-03-10" end-date="2023-03-14">2</workdays>
   <workdays start-date="2023-03-10" end-date="2023-03-15">3</workdays>
   <workdays start-date="2023-03-10" end-date="2023-03-16">4</workdays>
   <workdays start-date="2023-03-10" end-date="2023-03-17">5</workdays>
   <workdays start-date="2023-03-10" end-date="2023-03-20">6</workdays>
</output>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51