使用纯 XSLT 1.0 将日期时间转换为 UTC/GMT [英] Convert dateTime to UTC/GMT using pure XSLT 1.0

查看:44
本文介绍了使用纯 XSLT 1.0 将日期时间转换为 UTC/GMT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找不到这个问题的现有答案,所以我把它贴在这里.

I couldn't find an existing answer to this problem, so I am posting it here.

注意输入日期时间:

  • 可能有也可能没有小数秒;
  • 可能已经在 UTC/GMT,

这使过程复杂化.

示例输入:

<data>
    <datetime>2020-06-01T04:45:15+05:30</datetime>
    <datetime>2020-06-01T04:45:15.123+05:30</datetime>
    <datetime>2020-05-31T19:45:15-08:00</datetime>
    <datetime>2020-05-31T19:45:15.123-08:00</datetime>
    <datetime>2020-05-31T19:45:15Z</datetime>
    <datetime>2020-05-31T19:45:15.123Z</datetime>
</data>

预期输出:

<data>
  <datetime>2020-05-31T23:15:15Z</datetime>
  <datetime>2020-05-31T23:15:15.123Z</datetime>
  <datetime>2020-06-01T03:45:15Z</datetime>
  <datetime>2020-06-01T03:45:15.123Z</datetime>
  <datetime>2020-05-31T19:45:15Z</datetime>
  <datetime>2020-05-31T19:45:15.123Z</datetime>
</data>

推荐答案

以下解决方案首先测试给定的 dateTime 是否已经在 UTC/GMT 中.如果是,则将其原样传递给输出.否则,给定 dateTime 的各个组件:

The following solution starts by testing if the given dateTime is already in UTC/GMT. If it is, it is passed to the output as is. Otherwise, the individual components of the given dateTime:

  • 年;
  • 月;
  • 天;
  • 小时;
  • 分钟;
  • 秒;
  • 偏移时间;
  • 偏移分钟;
  • 偏移符号,

被提取出来.

接下来,将本地日期时间转换为自公元前 4714 年 11 月 24 日午夜(儒略日数纪元)以来经过的总秒数.UTC/GMT 的偏移量也转换为秒并从总数中减去.

Next, the local dateTime is converted to total number of seconds elapsed since midnight of November 24, 4714 BCE (the Julian Day Number epoch). The offset from UTC/GMT is also converted to seconds and subtracted from the total.

然后将结果转换回公历日期和时间,并格式化为 ISO 8601 日期时间.

The result is then converted back to Gregorian date and time-of-day and formatted as an ISO 8601 dateTime.

XSLT 1.0

<xsl:template name="dateTime-to-UTC">
    <xsl:param name="dateTime"/>
    <xsl:choose>
        <xsl:when test="contains($dateTime, 'Z')">
            <xsl:value-of select="$dateTime"/>
        </xsl:when>
        <xsl:otherwise>
            <!-- extract components -->
            <xsl:variable name="date" select="substring-before($dateTime, 'T')" />
            <xsl:variable name="time" select="substring-after($dateTime, 'T')" />
            <!-- date components -->
            <xsl:variable name="year" select="substring($date, 1, 4)" />
            <xsl:variable name="month" select="substring($date, 6, 2)" />
            <xsl:variable name="day" select="substring($date, 9, 2)" />
            <!-- time components -->
            <xsl:variable name="local-time" select="substring($time, 1, string-length($time) - 6)" />
            <xsl:variable name="hour" select="substring($local-time, 1, 2)" />
            <xsl:variable name="minute" select="substring($local-time, 4, 2)" />
            <xsl:variable name="second" select="substring($local-time, 7)" />
            <!-- offset components -->
            <xsl:variable name="offset" select="substring-after($time, $local-time)"/>
            <xsl:variable name="offset-sign" select="1 - 2 * starts-with($offset, '-')" />
            <xsl:variable name="offset-hour" select="substring($offset, 2, 2) * $offset-sign" />
            <xsl:variable name="offset-minute" select="substring($offset, 5, 2) * $offset-sign" />
            <!-- convert to seconds -->
            <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:variable name="jd" select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
            <xsl:variable name="total-seconds" select="86400*$jd + 3600*$hour + 60*$minute + $second - 3600*$offset-hour - 60*$offset-minute" />
            <!-- convert to date -->
            <xsl:variable name="new-jd" select="floor($total-seconds div 86400)"/>  
            <xsl:variable name="new-hour" select="floor($total-seconds mod 86400 div 3600)"/>
            <xsl:variable name="new-minute" select="floor($total-seconds mod 3600 div 60)"/>
            <xsl:variable name="new-second" select="$total-seconds mod 60"/>
            <xsl:variable name="f" select="$new-jd + 1401 + floor((floor((4 * $new-jd + 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)"/>
            <!-- output -->
            <xsl:value-of select="$Y"/>
            <xsl:value-of select="format-number($M, '-00')"/>
            <xsl:value-of select="format-number($D, '-00')"/>
            <xsl:text>T</xsl:text>
            <xsl:value-of select="format-number($new-hour, '00')"/>
            <xsl:value-of select="format-number($new-minute, ':00')"/>
            <xsl:value-of select="format-number($new-second, ':00.###')"/>
            <xsl:text>Z</xsl:text>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>


演示: https://xsltfiddle.liberty-development.net/艾因6

另见:https://stackoverflow.com/a/46196920/3016153

这篇关于使用纯 XSLT 1.0 将日期时间转换为 UTC/GMT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆