Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
421 views
in Technique[技术] by (71.8m points)

ms word - How to add 5 business days to an existing value xslt

I have a string called "DateSet" with the value "16/10/2008". I want to add 5 business days to that value. I assume i have to convert the value to something so that it knows it's a date.

I am using xslt 1.0, and using a custom software to convert xslt to a word document. Now it shows:

<w:p>
  <w:r>
    <w:t>Some text [DateSet]</w:t>
  </w:r>
</w:p>

Where [DateSet] 16/10/2008

But what i would like it to show is:

<w:p>
  <w:r>
    <w:t>Some text [DateSet+5business days]</w:t>
  </w:r>
</w:p>

Where [DateSet+5business days] should be showing 23/10/2008

Do I need to use ms:format-date and convert it somehow?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

From your description, it sounds as if you have isolated the date string from the context so you can work with it and replace it with the new date. Good. If that is not true, your first problem will be making it true.

The extension function ms:format-date() may be able to help you, but glancing at its documentation I don't see how.

Given a date, I think the easiest way to perform date arithmetic of the kind you need in XSLT 1.0 will be:

  1. Convert the date to an integer (e.g. a Julian day number).
  2. Perform the date arithmetic.
  3. Convert the resuting integer into a date.

To convert a date to an integer, the following template can be used; it's based on Robert G. Tantzen, "Algorithm 199: Conversions between calendar date and Julian day number" CACM 6.8 (Aug 1963): 444. It requires that you parse out the year, month, and day numbers from your date string and pass them in a parameters.

<xsl:template name="jday">
  <!--* JDay:  convert a triple of integers representing
  * Gregorian year, month, and day numbers to the
  * number of the Julian day beginning at noon on that
  * date.
  * Transcribed from Robert G. Tantzen, "Algorithm
  * 199:  Conversions between calendar date and Julian
  * day number" CACM 6.8 (Aug 1963): 444.
      *-->
  <xsl:param name="year" select="1963"/>
  <xsl:param name="month" select="08"/>
  <xsl:param name="day" select="13"/>

  <xsl:variable name="y">
<xsl:choose>
  <xsl:when test="$month > 2">
    <xsl:value-of select="$year"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="$year - 1"/>
  </xsl:otherwise>
</xsl:choose>
  </xsl:variable>
  <xsl:variable name="m">
<xsl:choose>
  <xsl:when test="$month > 2">
    <xsl:value-of select="$month - 3"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="$month + 9"/>
  </xsl:otherwise>
</xsl:choose>
  </xsl:variable>
  <xsl:variable name="d" select="$day"/>
  <xsl:variable name="c" select="floor($y div 100)"/>
  <xsl:variable name="ya" select="$y - 100 * $c"/>

  <!--* H holds the offset between Julian day 0
      * and the beginning of the common era.
      *-->
  <xsl:variable name="H" select="1721119"/>
  <!--* Calculate the Julian day that begins on the 
      * given date.
      *-->
  <xsl:value-of select="floor(($c * 146097) div 4) 
            + floor(($ya * 1461) div 4) 
            + floor((($m * 153) + 2) div 5) 
            + $d 
            + $H"/>

</xsl:template>

Performing the date arithmetic may be a little tricky: for weekdays, the date five business days later is (I guess) seven calendar days later, unless a holiday occurs in that period. For weekends, I guess the date five business days later is the next Friday. Given a Julian Day number $j, you can get the day of the week by calculating $j mod 7: 0 = Monday, 1 = Tuesday, ..., 6 = Sunday. So your calculation may look something like

<xsl:choose>
  <xsl:when test="$j mod 7 = 5">
    <xsl:value-of select="$j + 6"/>
  </xsl:when>
  <xsl:when test="$j mod 7 = 6">
    <xsl:value-of select="$j + 5"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="$j + 7"/>
  </xsl:otherwise>
</xsl:choose>

For holidays, you are going to have to consult some external source of information for the periods you are interested in; good luck.

Converting the resulting day number back to a calendar date can be done with the following template, again transcribed from Tantzen 1963:

<xsl:template name="jdate">
  <!--* JDate:  given a Julian day number, return an ISO
  * 8601 date.  
  * Transcribed from Robert G. Tantzen, "Algorithm
  * 199:  Conversions between calendar date and Julian
  * day number" CACM 6.8 (Aug 1963): 444.
      *-->
  <xsl:param name="j" select="2438255"/>

  <!--* dce:  days in the common era (i.e. since 
      * 0000-03-01; Tantzen uses 1 Mar, not 1 Jan,
      * as his epoch to simplify calculations). *-->
  <xsl:variable name="dce" select="$j - 1721119"/>

  <!--* cce:  full centuries in the common era. *-->
  <xsl:variable name="cce" 
                select="floor((4 * $dce - 1) div 146097)"/>

  <!--* dcc4:  days in current century, times 4. *-->
  <xsl:variable name="dcc4" 
                select="(4 * $dce - 1) - (146097 * $cce)"/>

  <!--* dcc:  days in current century. *-->
  <xsl:variable name="dcc4" 
                select="floor($dcc4 div 4)"/>

  <!--* ycc:  years in current century. *-->
  <xsl:variable name="ycc" 
                select="floor((4 * $dcc + 3) div 1461)"/>

  <!--* dcy4:  days in current year, times 4. *-->
  <xsl:variable name="dcy4" 
                select="(4 * $dcc + 3) - (1461 * $ycc)"/>

  <!--* dcy:  days in current year. *-->
  <xsl:variable name="dcy" 
                select="floor(($dcy4 + 4) div 4)"/>

  <!--* rgtm:  RGT month number (0 Mar, 1 Apr ... 12 Feb). *-->
  <xsl:variable name="rgtm" 
                select="floor((5 * $dcy - 3) div 153)"/>

  <!--* dcm5:  days in current month (minus 1) times 5. *-->
  <xsl:variable name="dcm5" 
                select="5 * $dcy - 3 - 153 * $rgtm"/>

  <!--* d:  day number in current month. *-->
  <xsl:variable name="d" 
                select="floor(($dcm5 + 5) div 5)"/>

  <!--* rgty:  RGT year number. *-->
  <xsl:variable name="rgty" 
                select="100 * $cce + $ycc"/>

  <!--* y:  Gregorian year number. *-->
  <xsl:variable name="y">
<xsl:choose>
  <xsl:when test="$rgtm &lt; 10">
    <xsl:value-of select="$rgty"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="$rgty + 1"/>
  </xsl:otherwise>
</xsl:choose>
  </xsl:variable>

  <!--* m:  Gregorian month number. *-->
  <xsl:variable name="m">
<xsl:choose>
  <xsl:when test="$rgtm &lt; 10">
    <xsl:value-of select="$rgtm + 3"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="$rgtm - 9"/>
  </xsl:otherwise>
</xsl:choose>
  </xsl:variable>

  <!--* Return value in ISO 8601 format *-->
  <xsl:value-of select="concat(
            format-number($y,'0000'),
            '-',
            format-number($m,'00'),
            '-',
            format-number($d,'00')
            )"/>
</xsl:template>

Note that as written, this returns the date in ISO format; you will want to change it if you want dd/mm/yyyy or mm/dd/yyyy or some other format.

Good luck.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...