Recipe4.4.Calculating Julian and Absolute Day Numbers from a Specified Date


Recipe 4.4. Calculating Julian and Absolute Day Numbers from a Specified Date

Problem

You have a date and would like to know the corresponding Julian day number and/or absolute day number.

Julian Day Versus Julian Dates

Do not make the mistake of confusing the Julian day with the Julian calendar. Joseph J. Scaliger has invented the Julian period so that every year could be associated with a positive number without having to worry about BC/AD. The period starts on January 1, 4713 BC (according to the Julian calendar) and lasts for 7980 years. Astronomers have used the Julian period to assign a unique number to every day since 1 January 4713 BC. This is the Julian day. As I write this chapter, the Julian day is 2,452,376. The curious can use the code in this section to determine the actual date. Another absolute numbering scheme used by N. Dershowitz and E. Reingold in their calendar algorithms begins on January 1, 1 AD. I refer to a number in their system as an absolute day number. Absolute day 1 corresponds to Julian Day 1,721,426.


Solution

XSLT 1.0

This template will give you the Julian day, given the year, month, and day:

<xsl:template name="ckbk:calculate-julian-day">      <xsl:param name="year"/>      <xsl:param name="month"/>      <xsl:param name="day"/>         <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) + $y * 365 +            floor($y div 4) - floor($y div 100) + floor($y div 400) -            32045"/>       </xsl:template>

Once you have a way to calculate the Julian day number, it is easy to create a template for determining the number of days between any two dates:

<xsl:template name="ckbk:date-difference">      <xsl:param name="from-year"/>      <xsl:param name="from-month"/>      <xsl:param name="from-day"/>      <xsl:param name="to-year"/>      <xsl:param name="to-month"/>      <xsl:param name="to-day"/>          <xsl:variable name="jd1">         <xsl:call-template name="ckbk:calculate-julian-day">          <xsl:with-param name="year" select="$from-year"/>            <xsl:with-param name="month" select="$from-month"/>            <xsl:with-param name="day" select="$from-day"/>        </xsl:call-template>      </xsl:variable>          <xsl:variable name="jd2">         <xsl:call-template name="ckbk:calculate-julian-day">          <xsl:with-param name="year" select="$to-year"/>            <xsl:with-param name="month" select="$to-month"/>            <xsl:with-param name="day" select="$to-day"/>        </xsl:call-template>      </xsl:variable>          <xsl:value-of select="$jd1 - $jd2"/> </xsl:template>

The following templates convert from a Julian day to a Gregorian date in the form YYYY/MM/DD. Use substring-before, substring-after, and TRanslate to parse or convert to the conventions of a particular locale:

<xsl:template name="ckbk:julian-day-to-julian-date">      <xsl:param name="j-day"/>          <xsl:call-template name="ckbk:julian-or-gregorian-date-elem">           <xsl:with param name="b" select="0"/>           <xsl:with param name="c" select="$j-day + 32082"/>      </xsl:call-template>     </xsl:template>     <xsl:template name="ckbk:julian-day-to-gregorian-date">      <xsl:param name="j-day"/>          <xsl:variable name="a" select="$j-day + 32044"/>      <xsl:variable name="b" select="floor((4 * $a + 3) div 146097)"/>      <xsl:variable name="c" select="$a - 146097 * floor($b div 4)"/>          <xsl:call-template name="ckbk:julian-or-gregorian-date-elem">           <xsl:with param name="b" select="$b"/>           <xsl:with param name="c" select="$c"/>      </xsl:call-template>           </xsl:template>     <!-- A utility that is used for both Gregorian and Julian calendars. --> <xsl:template name="ckbk:julian-or-gregorian-date-elem">      <xsl:param name="b"/>      <xsl:param name="c"/>          <xsl:variable name="d" select="floor((4 * $c + 3) div 1461)"/>      <xsl:variable name="e" select="$c - floor((1461 * $d) div 4)"/>      <xsl:variable name="m" select="floor((5 * $e + 2) div 153)"/>          <xsl:variable name="day"            select="$e - floor((153 * $m + 2) div 5) + 1"/>          <xsl:variable name="month"            select="$m + 3 - (12 * floor($m div 10))"/>          <xsl:variable name="year"            select="100 * $b + $d - 4800 + floor($m div 10)"/>          <xsl:value-of select="concat($year,'/',$month,'/',$day)"/>       </xsl:template>

You can easily convert between Julian days and absolute days with the following templates:

<xsl:template name="ckbk:julian-day-to-absolute-day">      <xsl:param name="j-day"/>      <xsl:value-of select="$j-day - 1721425"/> </xsl:template>     <xsl:template name="ckbk:absolute-day-to-julian-day">      <xsl:param name="abs-day"/>      <xsl:value-of select="$abs-day + 1721425"/> </xsl:template>

You can then express absolute day/Gregorian conversions in terms of the existing Julian day/Gregorian conversions:

<xsl:template name="ckbk:date-to-absolute-day">     <xsl:param name="year"/>     <xsl:param name="month"/>     <xsl:param name="day"/>          <xsl:call-template name="ckbk:julian-day-to-absolute-day">       <xsl:with-param name="j-day">         <xsl:call-template name="ckbk:date-to-julian-day">           <xsl:with-param name="year" select="$year"/>           <xsl:with-param name="month" select="$month"/>           <xsl:with-param name="day" select="$day"/>         </xsl:call-template>       </xsl:with-param>   </xsl:call-template> </xsl:template>     <xsl:template name="ckbk:absolute-day-to-date">   <xsl:param name="abs-day"/>      <xsl:call-template name="ckbk:julian-day-to-date">        <xsl:with-param name="j-day">             <xsl:call-template name="ckbk:absolute-day-to-julian-day">                  <xsl:with-param name="abs-day" select="$abs-day"/>             </xsl:call-template>        </xsl:with-param>   </xsl:call-template> </xsl:template>

XSLT 2.0

The need for Julian and absolute day functions in XSLT 2.0 is diminished because date math is directly supported. For example,

<dateDiff>  <xsl:value-of select="xs:date('2005-02-21') - xs:date('2005-01-01')"/>  </dateDiff>

results in:

<dateDiff>P51D</dateDiff>

However, some applications may need these values for other purposes. Here we choose to implement the 1.0 templates in terms of functions that take an xs:date rather than the individual components:

<xsl:function name="ckbk:calculate-julian-day">    <xsl:param name="date" as="xs:date"/>          <xsl:variable name="year" select="year-from-date($date)"  as="xs:integer"/>    <xsl:variable name="month" select="month-from-date($date)" as="xs:integer"/>    <xsl:variable name="day" select="month-from-date($date)" as="xs:integer"/>        <xsl:variable name="a" select="(14 - $month) idiv 12" as="xs:integer"/>    <xsl:variable name="y" select="$year + 4800 - $a" as="xs:integer"/>    <xsl:variable name="m" select="$month + 12 * $a - 3" as="xs:integer"/>        <xsl:sequence select="$day + ((153 * $m + 2) idiv 5) + $y * 365 +          floor($y div 4) - ($y idiv 100) + ($y idiv 400) - 32045"/>     </xsl:function>

Discussion

The Julian day and absolute day are useful because they greatly simplify other date algorithms. Other examples in this chapter reuse these conversions extensively. These numbering schemes act as a common currency for all the calendar systems in this chapter. Should you ever find yourself needing to convert a Hebrew date to a Muslim date, the sequence Muslim to Absolute to Hebrew will do the trick.




XSLT Cookbook
XSLT Cookbook: Solutions and Examples for XML and XSLT Developers, 2nd Edition
ISBN: 0596009747
EAN: 2147483647
Year: 2003
Pages: 208
Authors: Sal Mangano

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net