XSL 通过偏移比较将 UTC 时间转换为本地日期时间
XSL to convert UTC time to local datetime with an offset compare
我们接收相对于 UTC 时间的日期时间元素,例如 2004-04-12T13:20:00Z
。
我们想输出本地日期时间的日期时间,用相对于 UTC 时间的偏移量表示,如 2004-04-12T12:20:00-01:00
。
有人可以帮助在 XSLT 中实现这个吗?
或者是否存在实现此目的的函数模板?
假设 XML 测试文件是这样的
<?xml version="1.0"?>
<root>
<val>2004-04-12T13:20:00Z</val>
<val>2004-05-12T23:20:00Z</val>
<val>2004-06-12T00:20:00Z</val>
</root>
像这样的 XSLT-2.0 文件会将时区设置为 -1
:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="//val">
<xsl:variable name="t_offset" select="xs:dayTimeDuration('-PT1H')" /> <!-- set timezone to -1 hours -->
<xsl:variable name="time" select="xs:dateTime(normalize-space(text()))" />
<xsl:value-of select="$time" />
<xsl:value-of select="' '" />
<xsl:value-of select="adjust-dateTime-to-timezone($time, $t_offset)" /> <!-- adjust the time to the new timezone -->
<xsl:value-of select="' '" />
<xsl:value-of select="'------------------ '" />
</xsl:template>
</xsl:stylesheet>
它的输出是:
2004-04-12T13:20:00Z
2004-04-12T12:20:00-01:00
------------------
2004-05-12T23:20:00Z
2004-05-12T22:20:00-01:00
------------------
2004-06-12T00:20:00Z
2004-06-11T23:20:00-01:00
------------------
要将给定的日期时间值转换为 当前 本地时区,请使用 adjust-dateTime-to-timezone()
函数,而无需指定 timezone
参数。
例如:
<xsl:variable name="datetime">2004-04-12T13:20:00Z</xsl:variable>
<xsl:value-of select="adjust-dateTime-to-timezone($datetime)"/>
将return:
2004-04-12T12:20:00-01:00
如果在转换时,您系统的本地时间与 UTC 相差 -1 小时。
重要:
如果您的当地时间与 UTC 的偏差不是恒定的,而是由于夏令时而发生变化,这可能不会产生预期的结果。要将 2004 年 4 月的日期正确转换为当时的当地时间,您需要知道在该特定时间点与 UTC 的偏移量。 XSLT 没有此功能,您必须在另一个可以访问 Olson database.
的应用程序中进行转换
已添加:
以上所有内容都需要 XSLT 2.0。由于您现在已经阐明您实际上使用的是 XSLT 1.0:
- XSLT 1.0 无法知道与 UTC 的当前本地偏移量是多少 - 更不用说给定时间点的偏移量了。
- 有一种方法可以将给定的日期时间值调整为另一个
时区 - 如果您提供所需的偏移量作为参数
当调用 XSL 转换时(或者偏移量是
持续的)。
这是将 UTC 转换为 UTC -1:00(作为常量)的模板示例:
<xsl:template name="UTC-minus-one">
<xsl:param name="dateTime"/>
<xsl:variable name="date" select="substring-before($dateTime, 'T')" />
<xsl:variable name="time" select="substring-before(substring-after($dateTime, 'T'), 'Z')" />
<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)" />
<xsl:variable name="hour" select="substring($time, 1, 2)" />
<xsl:variable name="minute" select="substring($time, 4, 2)" />
<xsl:variable name="second" select="substring($time, 7)" />
<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" />
<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)"/>
<xsl:value-of select="concat($Y, format-number($M, '-00'), format-number($D, '-00'))"/>
<xsl:text>T</xsl:text>
<xsl:value-of select="concat(format-number($new-hour, '00'), format-number($new-minute, ':00'), format-number($new-second, ':00.###'))"/>
<xsl:text>-01:00</xsl:text>
</xsl:template>
假设您正在使用 Oracle SOA 套件进行转换。
xp20:subtract-dayTimeDuration-from-dateTime (/ns0:Your/@DateTime, concat ("PT", substring-after (substring-before (xp20:timezone-from-dateTime (xp20:current-dateTime() ), ":" ), "-0" ), "H" ) )
这应该可以解决您的问题
我们接收相对于 UTC 时间的日期时间元素,例如 2004-04-12T13:20:00Z
。
我们想输出本地日期时间的日期时间,用相对于 UTC 时间的偏移量表示,如 2004-04-12T12:20:00-01:00
。
有人可以帮助在 XSLT 中实现这个吗?
或者是否存在实现此目的的函数模板?
假设 XML 测试文件是这样的
<?xml version="1.0"?>
<root>
<val>2004-04-12T13:20:00Z</val>
<val>2004-05-12T23:20:00Z</val>
<val>2004-06-12T00:20:00Z</val>
</root>
像这样的 XSLT-2.0 文件会将时区设置为 -1
:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="//val">
<xsl:variable name="t_offset" select="xs:dayTimeDuration('-PT1H')" /> <!-- set timezone to -1 hours -->
<xsl:variable name="time" select="xs:dateTime(normalize-space(text()))" />
<xsl:value-of select="$time" />
<xsl:value-of select="' '" />
<xsl:value-of select="adjust-dateTime-to-timezone($time, $t_offset)" /> <!-- adjust the time to the new timezone -->
<xsl:value-of select="' '" />
<xsl:value-of select="'------------------ '" />
</xsl:template>
</xsl:stylesheet>
它的输出是:
2004-04-12T13:20:00Z
2004-04-12T12:20:00-01:00
------------------
2004-05-12T23:20:00Z
2004-05-12T22:20:00-01:00
------------------
2004-06-12T00:20:00Z
2004-06-11T23:20:00-01:00
------------------
要将给定的日期时间值转换为 当前 本地时区,请使用 adjust-dateTime-to-timezone()
函数,而无需指定 timezone
参数。
例如:
<xsl:variable name="datetime">2004-04-12T13:20:00Z</xsl:variable>
<xsl:value-of select="adjust-dateTime-to-timezone($datetime)"/>
将return:
2004-04-12T12:20:00-01:00
如果在转换时,您系统的本地时间与 UTC 相差 -1 小时。
重要:
如果您的当地时间与 UTC 的偏差不是恒定的,而是由于夏令时而发生变化,这可能不会产生预期的结果。要将 2004 年 4 月的日期正确转换为当时的当地时间,您需要知道在该特定时间点与 UTC 的偏移量。 XSLT 没有此功能,您必须在另一个可以访问 Olson database.
的应用程序中进行转换已添加:
以上所有内容都需要 XSLT 2.0。由于您现在已经阐明您实际上使用的是 XSLT 1.0:
- XSLT 1.0 无法知道与 UTC 的当前本地偏移量是多少 - 更不用说给定时间点的偏移量了。
- 有一种方法可以将给定的日期时间值调整为另一个 时区 - 如果您提供所需的偏移量作为参数 当调用 XSL 转换时(或者偏移量是 持续的)。
这是将 UTC 转换为 UTC -1:00(作为常量)的模板示例:
<xsl:template name="UTC-minus-one">
<xsl:param name="dateTime"/>
<xsl:variable name="date" select="substring-before($dateTime, 'T')" />
<xsl:variable name="time" select="substring-before(substring-after($dateTime, 'T'), 'Z')" />
<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)" />
<xsl:variable name="hour" select="substring($time, 1, 2)" />
<xsl:variable name="minute" select="substring($time, 4, 2)" />
<xsl:variable name="second" select="substring($time, 7)" />
<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" />
<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)"/>
<xsl:value-of select="concat($Y, format-number($M, '-00'), format-number($D, '-00'))"/>
<xsl:text>T</xsl:text>
<xsl:value-of select="concat(format-number($new-hour, '00'), format-number($new-minute, ':00'), format-number($new-second, ':00.###'))"/>
<xsl:text>-01:00</xsl:text>
</xsl:template>
假设您正在使用 Oracle SOA 套件进行转换。
xp20:subtract-dayTimeDuration-from-dateTime (/ns0:Your/@DateTime, concat ("PT", substring-after (substring-before (xp20:timezone-from-dateTime (xp20:current-dateTime() ), ":" ), "-0" ), "H" ) )
这应该可以解决您的问题