Главная » XSLT » Вычисление юлианского и абсолютного дня, соответствующих заданной дате

0

Задача

Зная дату, требуется найти соответствующий ей юлианский или абсолютный номер дня.

ЮЛИАНСКИЙ ДЕНЬ И ДАТА ПО ЮЛИАНСКОМУ КАЛЕНДАРЮ

Не путайте юлианский день с юлианским календарем. Джозеф Дж. Скали- гер (Joseph J. Scaliger) изобрел юлианский период, так чтобы каждому году можно было сопоставить целое положительное число, не заботясь о том, по какую сторону от начала новой эры он находится. Период начинается 1 января 4713 года до н.э. и длится 7980 лет. В астрономии юлианский период применяет­ся для того, чтобы ассоциировать с каждым днем, начиная с 1 января 4713 года до н.э. уникальное число, которое и называется юлианским днем. Эту главу я начал писать в юлианский день с номером 2 452 376. Любознательный читатель может воспользоваться приведенным рецептом, чтобы узнать соответствующую ему дату. Другую схему абсолютной нумерации дней применили Н. Дершовиц и Э. Рей­нгольд в своих календарных алгоритмах. В ней точкой отсчета является 1 янва­ря 1 года н.э. Номер дня в их системе я называю абсолютным номером дня. Абсолютный день 1 соответствует юлианскому дню 1 721 426.

Решение

XSLT 1.0

Следующий шаблон возвращает номер юлианского дня, если заданы год, ме­сяц и день.

<xsl:template name="date: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>

Зная, как вычислить номер юлианского дня, легко написать шаблон для вы­числения количества дней между любыми двумя датами:

<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>

Показанные ниже шаблоны преобразуют юлианский день в григориан­скую дату в формате ГГГГ/ММ/ДД. Чтобы привести эту дату к форме, соот­ветствующей конкретной локали, или выделить из нее отдельные компонен­ты, воспользуйтесь функциями substring-before, substring-after и translate.

<xsl:template name="date:julian-day-to-julian-date"> <xsl:param name="j-day"/>

<xsl:call-template name="date: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="date: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="date:julian-or-gregorian-date-elem"> <xsl:with-param name="b" select="$b"/> <xsl:with-param name="c" select="$c"/> </xsl:call-template>

</xsl:template>

<!– Вспомогательный шаблон, используемый и для григорианского, и для юлианского календаря –>

<xsl:template name="date: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="10 0 * $b + $d – 4800 + floor($m div 10)"/>

<xsl:value-of select="concat($year,’/,,$month,,/,,$day)"/>

С помощью следующих шаблонов нетрудно выполнить преобразование юли­анского дня в абсолютный и наоборот:

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

<xsl:template name="ckbk:julian-day-to-julian-day"> <xsl:param name="abs-day">

<xsl:value-of select="$abs-day + 1721425"/> </xsl:template>

Теперь можно выразить преобразование между абсолютным днем и григори­анским календарем в терминах уже имеющегося преобразования между юлианс­ким днем и григорианским календарем.

<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

В версии 2.0 необходимость в функциях вычисления юлианского и абсолют­ного дня не так насущна, поскольку поддержка операций с датами встроена в сам язык. Например:

<dateDiff>

<xsl:value-of select="xs:date(‘2 0 05-02-21′) – xs:date(‘2005-01-01′)"/> </dateDiff>

возвращает

<dateDiff>P51D</dateDiff>

Однако в некоторых приложениях эти функции могут понадобиться для дру­гих целей. Поэтому преобразуем рассмотренные выше шаблоны в функции, при­нимающие параметры типа xs:date вместо отдельных компонентов:

<xsl:function name="ckbk:calculate-julian-day" as="xs:integer"> <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>

Обсуждение

Юлианский и абсолютный день полезны, потому что существенно упрощают другие алгоритмы работы с датами. В этой главе мы часто будем прибегать к та­ким преобразованиям. Подобные схемы нумерации играют роль единой валюты для всех рассматриваемых календарных систем. Если вам потребуется перевести дату из еврейского календаря в мусульманский, достаточно будет выполнить про­межуточное приведение к абсолютному дню.

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии