使用纯 XSLT 1.0 将日期时间转换为 UTC/GMT [英] Convert dateTime to UTC/GMT using pure XSLT 1.0
问题描述
我找不到这个问题的现有答案,所以我把它贴在这里.
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屋!