如何在XSLT 1.0中将ISO 8601日期/时间转换为毫秒?

时间:2013-08-12 18:04:47

标签: google-chrome xslt xslt-1.0 iso8601

如何使用XSLT 1.0将ISO 8601 2013-08-13T17:57:55Z日期/时间文本转换为“自纪元以来的毫秒数”?更具体地说,谷歌Chrome的XSLT版本。

2 个答案:

答案 0 :(得分:2)

扩展朱利安日期的算法由我的老经理(嗨,乔治!)教我,他依次从 ACM的收集算法获得它(虽然它似乎不包括在内)在online version of CALGO中,我无法找到算法编号,发布日期或作者[但请参阅下面的Postscript]),以下模板计算了时区Z中给定的ISO 8601时间戳,自Julian Day 0开始以来的毫秒数,不包括闰秒。朱利安日0日开始于公元前4713年1月1日中午朱利安历;公元前4714年11月24日中午公历。

检查输入是否正常,调整以使用不同的时期,扩展以处理Z以外的时区,以及处理闰秒和日期之前的延伸都是留给读者的练习。 (或者你可以打电话给Javascript,但的乐趣在哪里?)

<xsl:template name="ts2i">
  <!--* timestamp to integer:  convert an ISO 8601 time stamp
      * to the number of milliseconds since an epoch.
      * Our epoch is 1 January 4713 BCE (Julian!),
      * which is Julian day 0.
      * To use 1970-01-01T00:00:00Z as the epoch,
      * subtract 210866760000000 ms.
      *-->
  <xsl:param name="ts"/>
  <!--* checking the timestamp for bad data is left as an
      * exercise of the reader.  Our contract is simpler:
      * give me a correct timestamp in time zone Z, for a 
      * date on or after 0001-01-01, and I'll
      * give you a correct answer (modulo overflow).
      *-->
  <!--* yyyy-mm-ddThh:mm:ss.sss...Z 
      * ....|....|....|....|...   | 
      * 1   5   10   15   20      n
      *-->

  <!--* Parse out c, y, m, d, hh, mm, ss (for century, 
      * years in current century, months since February, 
      * days in current month, hours, minutes, seconds).
      * the y and m values are adjusted to make the 
      * year begin 1 March (so leap day is always the last
      * day of the year).
      *-->
  <xsl:variable name="y0" select="substring($ts,1,4)"/>
  <xsl:variable name="m0" select="substring($ts,6,2)"/>
  <xsl:variable name="d"  select="substring($ts,9,2)"/>
  <xsl:variable name="y1">
    <xsl:choose>
      <xsl:when test="$m0 &lt; 3"><xsl:value-of select="$y0 - 1"/></xsl:when>
      <xsl:otherwise><xsl:value-of select="$y0"/></xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:variable name="m" select="($m0 + 9) mod 12"/>
  <xsl:variable name="c" select="floor($y1 div 100)"/>
  <xsl:variable name="y" select="($y1 mod 100)"/>
  <xsl:variable name="hh" select="substring($ts,12,2)"/>
  <xsl:variable name="mm" select="substring($ts,15,2)"/>
  <xsl:variable name="s0" select="substring($ts,18)"/>
  <xsl:variable name="ss">
    <xsl:choose>
      <xsl:when test="contains($s0,'Z')">
        <xsl:value-of select="substring-before($s0,'Z')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$s0"/>    
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <!--* H holds the offset in days between Julian day 0
      * and the beginning of the common era.
      * J holds the offset in ms between midnight and
      * noon, when Julian day 0 actually began.
      *-->
  <xsl:variable name="H" select="1721119"/>
  <xsl:variable name="J" select="43200000"/>

  <!--* Calculate the Julian day that begins on the 
      * given date.  There are 146097 days in each
      * 400-year period (including 25 leap days),
      * 1461 in each 4-year period, and there are
      * (($m * 153) + 2) div 5 days in $m months 
      * elapsed since 1 March.
      * This is straight from the Collected Algorithms.
      *-->
  <xsl:variable name="j" select="floor(($c * 146097) div 4) 
                                 + floor(($y * 1461) div 4) 
                                 + floor((($m * 153) + 2) div 5) 
                                 + $d + $H"/>

  <!--* Calculate the milliseconds since the beginning
      * of Julian day 0.  This is my extension, and 
      * it could have an off-by-one error.
      *-->
  <xsl:value-of select="$j   * 86400000
                        + $hh * 3600000
                        + $mm *   60000
                        + $ss *    1000
                        - $J"/>
</xsl:template>

当给出输入值&#34; 2013-08-13T17:57:55Z&#34;时,给定的模板返回数值2.12243176675e + 14,即212243176675000.

正如其中一篇评论中所提到的,当我写这篇文章时,我担心溢出,但XSLT 1.0数字是IEEE双打,因此(我相信)52位的尾数。因此,在接下来的几千年里,溢出不太可能是一个问题;你的毫秒将不会受到四舍五入的错误,直到138001年四月15日左右。

后记: ACM Digital Library中的一点研究发现了我认为必须是我的经理George Yanos学习这种算法的来源:Robert G. Tantzen,&#34 ;算法199:日历日期和朱利安日数之间的转换&#34;, ACM的通信 6。8(1963年8月):444。我注意到Tantzen没有解释任何魔术常数,这给出了他简洁的Algol代码充满了神秘色彩。

答案 1 :(得分:1)

唯一的方法是调用Javascript代码。