<!--
     XSLT Gregorian to Islamic date conversion

     translated fron parts of the JavaScipt libraries from
     http://www.fourmilab.ch/documents/calendar/

     see  https://www.ibm.com/developerworks/community/blogs/HermannSW/
                  entry/gregorian_to_islamic_date_conversion
-->
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:date="http://exslt.org/dates-and-times"
  xmlns:func="http://exslt.org/functions"
  xmlns:fml="http://www.fourmilab.ch/documents/calendar/"
  xmlns:dp="http://www.datapower.com/extensions"
  extension-element-prefixes="dp"
>
  <xsl:output omit-xml-declaration="no" />

  <!-- demonstration, output "now" as Islamic date -->    
  <xsl:template match="/">
    <xsl:variable name="now" select="date:date-time()"/>    

    <xsl:value-of select="fml:gregorian_to_islamic($now)"/>
  </xsl:template>
  

  <xsl:variable name="GREGORIAN_EPOCH" select="1721425.5"/>

  <xsl:variable name="ISLAMIC_EPOCH" select="1948439.5"/>

  <xsl:variable name="ISLAMIC_WEEKDAYS">
    <d>al-'ahad</d> <d>al-'ithnayn</d> <d>ath-thalatha'</d> <d>al-'arb`a'</d>
    <d>al-khamis</d> <d>al-jum`a</d> <d>as-sabt</d>
  </xsl:variable>

  <xsl:variable name="ISLAMIC_MONTHS">
    <m>Muharram</m> <m>Safar</m> <m>Rabi`al-Awwal</m> <m>Rabi`ath-Thani</m>
    <m>Jumada l-Ula</m> <m>Jumada t-Tania</m> <m>Rajab</m> <m>Sha`ban</m>
    <m>Ramadan</m> <m>Shawwal</m> <m>Dhu l-Qa`da</m> <m>Dhu l-Hijja</m>
  </xsl:variable>

  <func:function name="func:min">
    <xsl:param name="a"/>  <xsl:param name="b"/>

    <func:result>
      <xsl:choose>
        <xsl:when test="$a > $b"><xsl:value-of select="$b"/></xsl:when>
        <xsl:otherwise><xsl:value-of select="$a"/></xsl:otherwise>
      </xsl:choose>
    </func:result>
  </func:function>

  <func:function name="fml:jwday">
    <xsl:param name="j"/>

    <func:result select="floor($j + 1.5) mod 7"
    />
  </func:function>

  <func:function name="fml:leap_gregorian">
    <xsl:param name="year"/>

    <func:result select="
           (($year mod 4) = 0) and
            (not((($year mod 100) = 0) and (($year mod 400) != 0)))"
    />
  </func:function>

  <func:function name="fml:gregorian_to_jd">
    <xsl:param name="year"/> <xsl:param name="month"/> <xsl:param name="day"/>

    <xsl:variable name="term">
      <xsl:choose>
        <xsl:when test="$month &lt;= 2">0</xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="fml:leap_gregorian($year)">-1</xsl:when>
            <xsl:otherwise>-2</xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>    
      </xsl:choose>
    </xsl:variable>

    <func:result select="
           ($GREGORIAN_EPOCH - 1) +
           (365 * ($year - 1)) +
           floor(($year - 1) div 4) +
           (-floor(($year - 1) div 100)) +
           floor(($year - 1) div 400) +
           floor((((367 * $month) - 362) div 12) +
           $term +
           $day)
    "/>
  </func:function>

  <func:function name="fml:islamic_to_jd">
    <xsl:param name="year"/> <xsl:param name="month"/> <xsl:param name="day"/>

    <func:result select="
           ($day +
            ceiling(29.5 * ($month - 1)) +
            ($year - 1) * 354 +
            floor((3 + (11 * $year)) div 30) +
            $ISLAMIC_EPOCH) - 1"
    />
  </func:function>

  <func:function name="fml:jd_to_islamic">
    <xsl:param name="jd0"/>

    <xsl:variable name="jd" select="floor($jd0) + 0.5"/>
    <xsl:variable name="year" 
      select="floor(((30 * ($jd - $ISLAMIC_EPOCH)) + 10646) div 10631)"
    />
    <xsl:variable name="month" select="
      func:min(
        12,
        ceiling(($jd - (29 + fml:islamic_to_jd($year, 1, 1))) div 29.5) + 1
      )"
    />
    <xsl:variable name="day" 
      select="($jd - fml:islamic_to_jd($year, $month, 1)) + 1"
    />

    <func:result>
      <year> <xsl:value-of select="$year"/> </year>
      <month><xsl:value-of select="$month"/></month>
      <day>  <xsl:value-of select="$day"/>  </day>
    </func:result>
  </func:function>

  <func:function name="fml:gregorian_to_islamic">
    <xsl:param name="date"/>

    <xsl:variable name="year" select="date:year($date)"/>
    <xsl:variable name="mon"  select="date:month-in-year($date)"/>
    <xsl:variable name="mday" select="date:day-in-month($date)"/>
    <xsl:variable name="hour" select="date:hour-in-day($date)"/>
    <xsl:variable name="min"  select="date:minute-in-hour($date)"/>
    <xsl:variable name="sec"  select="date:second-in-minute($date)"/>

    <xsl:variable name="j" select="
        fml:gregorian_to_jd($year, $mon, $mday) +
           (floor($sec + 60 * ($min + 60 * $hour) + 0.5) div 86400.0)"
    />

    <xsl:variable name="weekday" select="fml:jwday($j)"/>

    <xsl:variable name="iscal" select="fml:jd_to_islamic($j)"/>

    <func:result select="concat(
                           $iscal/year, ' ',
                           $ISLAMIC_MONTHS/*[number($iscal/month)], ' ',
                           $iscal/day,
                           ' yawm ', $ISLAMIC_WEEKDAYS/d[1 + $weekday]
                         )"
    />
  </func:function>

</xsl:stylesheet>