如何基于日期范围实现BST/BWT等时段输出6am-6am的XSLT配置问询
解决英国时区下ValidityPeriod统一输出6am至6am的问题
嘿,这个问题我刚好有思路,咱们一步步来搞定它!核心需求很明确:不管是在英国冬令时(BWT)、夏令时(BST)还是长短日时段,都要把输入的「当日4UTC至次日4UTC」的ValidityPeriod,转换成对应英国本地时间的「当日6am至次日6am」,而不是现在BST时段出错的5am至5am。
问题根源分析
BST时段英国本地时间比UTC快1小时,输入的4UTC在BST时对应本地5am,系统如果直接按时区偏移转换输出,就会错误地生成5am本地到5am本地的时段。咱们要做的是基于固定日期范围判断时区,再手动转换到正确的UTC时间,而不是依赖自动时区偏移。
具体实现方案(以XSLT 2.0/3.0为例)
XSLT 2.0+支持原生的日期时间类型和范围比较,处理起来会很方便。
1. 定义各时段的固定日期范围
先把用户给出的时段定义成变量,方便后续判断:
<!-- 英国冬令时(BWT)日期范围 --> <xsl:variable name="bwt-start" select="xs:date('2018-10-28')"/> <xsl:variable name="bwt-end" select="xs:date('2019-03-31')"/> <!-- 英国夏令时(BST)日期范围 --> <xsl:variable name="bst-start" select="xs:date('2019-03-31')"/> <xsl:variable name="bst-end" select="xs:date('2020-10-27')"/>
2. 提取输入并转换为本地日期
从输入的ValidityPeriod属性中提取起始UTC时间,再判断它对应的英国本地日期属于哪个时段:
<!-- 提取输入的起始UTC时间 --> <xsl:variable name="input-start-utc" select="xs:dateTime(substring(@v, 1, 19))"/> <!-- 确定对应的英国本地日期 --> <xsl:variable name="local-date" as="xs:date"> <xsl:choose> <!-- BWT时段:UTC日期和本地日期一致 --> <xsl:when test="xs:date($input-start-utc) ge $bwt-start and xs:date($input-start-utc) le $bwt-end"> <xsl:sequence select="xs:date($input-start-utc)"/> </xsl:when> <!-- BST时段:UTC日期和本地日期一致(4UTC对应本地5am,仍属同一天) --> <xsl:when test="xs:date($input-start-utc) ge $bst-start and xs:date($input-start-utc) lt $bst-end"> <xsl:sequence select="xs:date($input-start-utc)"/> </xsl:when> <!-- 长短日时段:按用户需求,这里统一处理为对应本地日期 --> <xsl:otherwise> <xsl:sequence select="xs:date($input-start-utc)"/> </xsl:otherwise> </xsl:choose> </xsl:variable>
3. 生成目标时段并转换回UTC
先构建本地时间的6am至次日6am,再根据时段转换为对应的UTC时间:
<!-- 构建本地时间的起始和结束 --> <xsl:variable name="target-local-start" select="xs:dateTime(concat($local-date, 'T06:00:00'))"/> <xsl:variable name="target-local-end" select="xs:dateTime(concat($local-date + xs:dayTimeDuration('P1D'), 'T06:00:00'))"/> <!-- 转换为UTC时间 --> <xsl:variable name="target-utc-start" as="xs:dateTime"> <xsl:choose> <xsl:when test="$local-date ge $bwt-start and $local-date le $bwt-end"> <!-- BWT:本地6am = UTC 6am --> <xsl:sequence select="$target-local-start"/> </xsl:when> <xsl:when test="$local-date ge $bst-start and $local-date lt $bst-end"> <!-- BST:本地6am = UTC 5am(减去1小时) --> <xsl:sequence select="$target-local-start - xs:dayTimeDuration('PT1H')"/> </xsl:when> <xsl:otherwise> <!-- 长短日时段:根据实际时区偏移调整,比如长日按UTC+1,短日按UTC+0 --> <xsl:sequence select="$target-local-start - (if ($local-date ge xs:date('2019-04-01') and $local-date lt xs:date('2019-10-27')) then xs:dayTimeDuration('PT1H') else xs:dayTimeDuration('PT0H'))"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="target-utc-end" as="xs:dateTime"> <xsl:choose> <xsl:when test="$local-date ge $bwt-start and $local-date le $bwt-end"> <xsl:sequence select="$target-local-end"/> </xsl:when> <xsl:when test="$local-date ge $bst-start and $local-date lt $bst-end"> <xsl:sequence select="$target-local-end - xs:dayTimeDuration('PT1H')"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$target-local-end - (if ($local-date ge xs:date('2019-04-01') and $local-date lt xs:date('2019-10-27')) then xs:dayTimeDuration('PT1H') else xs:dayTimeDuration('PT0H'))"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <!-- 输出最终的ValidityPeriod --> <ValidityPeriod v="{concat($target-utc-start, '/', $target-utc-end)}"/>
关键注意事项
- 日期范围判断要基于本地日期:夏令时切换是在英国本地时间进行的,比如2019-03-31本地凌晨1点切换到2点,所以UTC时间T00:00到T01:00属于BWT,之后属于BST,测试时要覆盖这类切换日的场景。
- XSLT 1.0兼容方案:如果只能用XSLT 1.0,需要手动拆分日期字符串(提取年、月、日的数字)来进行范围比较,比如用
substring函数拆分后转成数字再判断。 - 长短日的处理:如果用户后续需要恢复长短日的特殊输出(6am-5am/6am-7am),只需要在
otherwise分支里添加对应的判断逻辑即可,现在咱们是统一输出6am-6am,所以按时区偏移处理。
内容的提问来源于stack exchange,提问作者Zakariya Kasu
相关产品推荐
相关产品推荐

