Reputation: 21
I have to find the next 3rd Wednesday of a month and I can't seem to come up with a good solution on XSLT to do this. For instance, today is August 11th so the next 3rd Wednesday of the month is August 16th. But if today is August 17th then the next 3rd Wednesday of the month will be Sept 20th.
Is there anyway to do this in XSLT 1.0?
Upvotes: 1
Views: 389
Reputation: 117073
Interesting problem - let's make it more generic:
<xsl:template name="Nth-weekday-of-month">
<xsl:param name="year"/>
<xsl:param name="month"/><!-- 1..12 = Jan..Dec -->
<xsl:param name="weekday"/><!-- 0..6 = Sun..Sat -->
<xsl:param name="N"/>
<!-- month starts on ... -->
<xsl:variable name="first-of-month">
<xsl:call-template name="JDN">
<xsl:with-param name="year" select="$year" />
<xsl:with-param name="month" select="$month" />
<xsl:with-param name="day" select="1" />
</xsl:call-template>
</xsl:variable>
<!-- ... day of week -->
<xsl:variable name="dow-first-of-month" select="($first-of-month + 1) mod 7"/>
<!-- distance to next day-of-week -->
<xsl:variable name="diff" select="(7 + $weekday - $dow-first-of-month) mod 7"/>
<!-- next day-of-week -->
<xsl:call-template name="GD">
<xsl:with-param name="JDN" select="$first-of-month + $diff + 7*($N - 1)" />
</xsl:call-template>
</xsl:template>
<xsl:template name="JDN">
<xsl:param name="year"/>
<xsl:param name="month"/>
<xsl:param name="day"/>
<!-- calculate JDN -->
<xsl:variable name="a" select="floor((14 - $month) div 12)"/>
<xsl:variable name="y" select="$year + 4800 - $a"/>
<xsl:variable name="m" select="$month + 12*$a - 3"/>
<xsl:value-of select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
</xsl:template>
<xsl:template name="GD">
<xsl:param name="JDN"/>
<xsl:variable name="f" select="$JDN + 1401 + floor((floor((4 * $JDN + 274277) div 146097) * 3) div 4) - 38"/>
<xsl:variable name="e" select="4*$f + 3"/>
<xsl:variable name="g" select="floor(($e mod 1461) div 4)"/>
<xsl:variable name="h" select="5*$g + 2"/>
<xsl:variable name="D" select="floor(($h mod 153) div 5 ) + 1"/>
<xsl:variable name="M" select="(floor($h div 153) + 2) mod 12 + 1"/>
<xsl:variable name="Y" select="floor($e div 1461) - 4716 + floor((14 - $M) div 12)"/>
<xsl:value-of select="$Y" />
<xsl:value-of select="format-number($M, '-00')"/>
<xsl:value-of select="format-number($D, '-00')"/>
</xsl:template>
Example of call:
<xsl:call-template name="Nth-weekday-of-month">
<xsl:with-param name="year" select="2017" />
<xsl:with-param name="month" select="8" />
<xsl:with-param name="weekday" select="3" />
<xsl:with-param name="N" select="3" />
</xsl:call-template>
returns 2017-08-16
, the date of the 3rd Wednesday in August 2017.
Demo showing calculation of the 3rd Wednesday in every month in the years 2014-2017: http://xsltransform.net/a9Gixf/1
Upvotes: 3