How to calculate the time difference (duration) in

2019-05-14 22:37发布

I use xlstproc to transform some xml file to another xml format file, during transformation, I need to calculate the time difference value (durations in seconds or minutes:seconds) between start and end fields.

... <start>2011-12-13 16:15:26</start> <end>2011-12-13 16:17:27</end> ...

I found a Template Syntax, but failed to make use of it.

<xsl:call-template name="date:duration">
  <xsl:with-param name="seconds" select="number" />?
</xsl:call-template>

Would appreciate somebody can give me a hint how to achieve my goal. Thanks in advance!

标签: xml xslt
1条回答
Lonely孤独者°
2楼-- · 2019-05-14 23:06

I did some of your work for you and found this date:duration function, which you seem to be trying to use. However, date:duration converts a number of seconds into a duration formatted string, whereas you want to find the difference (duration) between two datetime strings.

You probably want date:difference instead. If you read the documentation for this function/template, you'll find this about the arguments:

The two dates must both be right-truncated date/time strings in one of the formats defined in [XML Schema Part 2: Datatypes]. ... The permitted formats are as follows...

xs:dateTime (CCYY-MM-DDThh:mm:ss)
...

There are italics there in the original: CCYY-MM-DDThh:mm:ss except the T is not italicized. In other words, the time strings need a literal T between the date and the time, whereas yours have a space.

So I would suggest fixing that:

<start>2011-12-13T16:15:26</start>
  <end>2011-12-13T16:17:27</end>

Pass the start and end strings as parameters to the template. You can do this by just passing the start and end element nodes, which will be automatically converted to strings based on their text content:

<xsl:variable name="time-diff-dur">
  <xsl:call-template name="date:difference">
    <xsl:with-param name="start" select="start" />
    <xsl:with-param name="end" select="end" />
  </xsl:call-template>
</xsl:variable>
<!-- The above returns a duration formatted string, so convert that to seconds: -->
<xsl:variable name="time-diff-sec">
  <xsl:call-template name="date:seconds">
    <xsl:with-param name="seconds" select="$time-diff-dur" />?
  </xsl:call-template>
</xsl:variable>

This code assumes that the context node is the parent of the <start> and <end> elements. After the above code, the variable $time-diff-sec will contain a result tree fragment, which can be converted to a number using number($time-diff-sec) if necessary.

Let us know whether that works. If not, state specifically what the result was and how it differs from what you expected.

Update:

I just noticed that you are using xsltproc (which uses libxslt). According to this documentation, libxslt supports date:difference (and date:seconds) natively. So you can call these functions as functions instead of defining a named template and calling it as a template. That would be a lot less code for you, albeit less portable:

<xsl:variable name="time-diff-sec"
    select="date:seconds(date:difference(start, end))" />

As before, you will need to declare the date namespace prefix somewhere, usually on your xsl:stylesheet element:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="http://exslt.org/dates-and-times"
    extension-element-prefixes="date">

Update 2:

See this answer for a portable XSLT 1.0 template to convert a date string to number of seconds, which allows you to easily subtract one date from another. (Thanks to Sam B for that comment).

查看更多
登录 后发表回答