This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 4856 - [FO11] arithmetic on durations
Summary: [FO11] arithmetic on durations
Status: CLOSED WONTFIX
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: Functions and Operators 3.0 (show other bugs)
Version: Working drafts
Hardware: PC Windows XP
: P2 enhancement
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-07-13 14:53 UTC by Michael Kay
Modified: 2009-07-07 15:48 UTC (History)
3 users (show)

See Also:


Attachments

Description Michael Kay 2007-07-13 14:53:13 UTC
Enhancement request.

There is no logical reason why arithmetic on durations should be confined to the two subtypes xs:yearMonthDuration and xs:dayTimeDuration. All the various permitted combinations:

(a) duration +|- duration
(b) duration *|div number
(c) date|time|dateTime +|- duration

are perfectly well-defined on all durations, and easily specified by decomposing the duration into its two parts. For (a) the result should be the least common supertype of the operand types; for (b) it should be the same as the operand type.

Generalizing these operations to work on the primitive type will simplify the specification, and is therefore likely to simplify implementations, as well as providing useful functionality for users who have chosen to use the type xs:duration (or their own subtypes thereof) in their schemas.

The main rationale, however, is the removal of an arbitrary restriction that has no justification and delivers no benefits.
Comment 1 Frans Englich 2007-07-16 08:40:18 UTC
You suggest this as an errata, or as a XQuery 1.1 feature?
Comment 2 Michael Kay 2007-07-16 08:48:30 UTC
I thought I made it clear in both the text of the entry and in its classification that this was an enhancement request.
Comment 3 Michael Kay 2007-07-26 14:52:49 UTC
Since raising this I've encountered a use case, where a user defined his own subtype of xs:duration in his schema. He couldn't define it as a subtype of xs:dayTimeDuration, because that's not a type that XML Schema 1.0 recognizes, so it had to be his own type which was equivalent in all but name. 

(I'm not sure that we consciously recognized when we moved the types from the xdt into the xs namespace, that this would have the consequence that users can no longer use these types in a 1.0 schema.)

Arguably this problem will disappear over time, but people will want to write schemas that work under Schema 1.0 for many years to come, and there's no logical reason why we should require someone to cast to our subtypes in cases where there's no logical need for it.
Comment 4 Michael Kay 2007-11-16 09:28:47 UTC
Enhancement request: reclassified under F&O version 1.1
Comment 5 zhen hua liu 2008-04-29 00:17:09 UTC
The right solution to me is to move xs:dayTimeDuration and xs:yearMonthDuration into XML Schema 1.0.
Comment 6 Michael Kay 2008-04-29 00:26:32 UTC
>The right solution to me is to move xs:dayTimeDuration and xs:yearMonthDuration
into XML Schema 1.0.

I assume you're suggesting that as a solution to the problem mentioned in comment #3, rather than the original requirement?

I know that W3C is displaying a somewhat flexible attitude to version numbering at the moment, but surely you're not suggesting that new derived types can be added to a spec that has been out for 7 years without changing the version number? These types are being added to XML Schema 1.1.
Comment 7 Colin Adams 2008-04-29 07:36:01 UTC
By "somewhat flexible approach to version numbering" I assume you are refering to the Ninteen Eighty Four style of rewriting history that is being attempted with XML 1.0 Fifth Edition?

If this is passed, then anything goes, and so Zhen Hua Liu's suggestion becomes "reasonable" (in a Newspeak kind of way).

I propose we simply rename XSLT 2.0 as XSLT 1.0, in the same spirit. That way, noone will have to remember version numbers anymore.

Comment 8 Oliver Hallam 2008-05-14 17:07:45 UTC
If a) was to be allowed then you would have to change the definition of a duration:

Consider xs:duration("P1Y") - xs:duration("P1D").

This currently has no (valid) lexical value.
Comment 9 Michael Kay 2008-05-14 17:19:34 UTC
Re comment #8 - good point. Addition works fine, subtraction doesn't.
Comment 10 Benjamin Nguyen 2008-09-12 13:39:31 UTC
After checking ISO 8601:2004 [1], duration are indeed defined as non-negative : 

"duration
non-negative quantity attributed to a time interval, the value of which is equal to the difference between the
time points of the final instant and the initial instant of the time interval, when the time points are quantitative
marks"

XML-Schema [2] allows negative intervals : "One could also indicate a duration of minus 120 days as: -P120D."
This does not seem to be allowed by ISO.

However, XML-Schema does not allow partial negative values inside a duration i.e., "P1Y-1D" in order to indicate "a year minus a day" is forbidden.
Note that this is explicitly forbidden, since the values representing years, months, days, etc. are defined as unsigned integers (3.2.6.1)
Also note that in Functions and Operators [3] it is indicated in 10.2 that the values are xs:integers (xs:decimal for the seconds but this is not important)

A simple proposal (although conflicting with ISO 8601) would be to *allow* negative values to the subparts of a duration, i.e., "P1Y-1M" would be accepted as valid.
In this case, it would directly be possible to use the algebra as proposed by Mike Kay by decomposing a duration into a xs:yearMonthDuration part (with + and - operators) and a xs:dayTimeDuration (with + and - operators)
We suggest in fact allowing only negative values for the xs:yearMonthDuration and/or xs:dayTimeDuration parts, i.e., "P1Y-1M" would not be acceptable, since "P1Y-1M" = "P11M" but "P1Y-1D" would be, since it is in fact "P1Y" + "-P1D"

Let us also stress that in principle, according to ISO-8601 a duration can only occur in the following contexts :
"
a) by a start and an end;
b) by a duration and context information;
c) by a start and a duration;
d) by a duration and an end.
"

The only delicate case is case b) since it is the only case where "P1Y-1D" can be ambiguous : it would not evaluate to the same value in xs:dayTimeDuration if added to 2000-01-01T00:00:00Z or 1999-01-01T00:00:00Z
In the first case it is 365 days, in the latter 364, but again "context information" means that in both cases "P1Y-1D" makes sense.

Regards,

Benjamin Nguyen & Tristan Allard


[1] ISO 8601:2004, http://isotc.iso.org/livelink/livelink/4021199/ISO_8601_2004_E.zip?func=doc.Fetch&nodeid=4021199
[2] XML Schema : Datatypes, http://www.w3.org/TR/xmlschema-2/
[3] XQuery functions and Operators, http://www.w3.org/TR/xpath-functions/
Comment 11 Michael Kay 2008-09-13 14:03:51 UTC
I'm not sure how comment #10 helps us. We're concerned with defining operations on the data types defined in XML Schema 1.0 (and 1.1). What ISO 8601 says has no relevance (especially the 2004 edition); and while it's interesting to observe that a data type that allowed "one year minus a day" would achieve closure under subtraction, F+O doesn't have the opportunity to introduce such a type so it's somewhat out of scope.
Comment 12 Benjamin Nguyen 2008-09-16 14:21:17 UTC
Problem 1:

* xs:dateTime + xs:duration *

It is impossible to define addition and subtraction on the general type xs:duration (without allowing negative values, which means changing the definition of the type in XML Schema) due to the fact we can not convert days into years or months. However, if an anchor xs:dateTime is provided, then it seems possible to compute addition and subtraction of any sort of xs:duration to this xs:dateTime, although this is not possible for the moment for the current spec

Basically said, we would like to include an op:add-duration-to-dateTime and op:subtract-duration-from-dateTime, we think this is part of the enhancement. 

let $date1 := xs:dateTime("2008-09-15T00:00:00Z")
let $duration1 := xs:duration("P1Y")
let $duration2 := xs:duration("-P1D")
return $date1 + $duration1 + $duration2

->  2009-09-14T00:00:00Z

Here we are able to define non ambiguously the resulting date due to the priority of operators (i.e. we first compute $date + $duration1, which returns a xs:dateTime then we add "-P1D" to this xs:dateTime).

In order to be able to add an arbitrary xs:duration, we need to define the priority between the "subparts" of the xs:duration when a "year" changes length according to the intermediate result. Remember that 2000 was a leap year in the following example

let $date2 := xs:dateTime("2000-01-01T00:00:00Z")
let $duration3 := xs:duration("P1Y60D")

return $date2 + $duration3

The result is undefined, since it depends on the order of the addition:
case 1 : 2000-01-01T00:00:00Z + P1Y +P60D = 2001-03-02T00:00:00Z -> here P1Y == P366D
case 2 : 2000-01-01T00:00:00Z + P60D +P1Y = 2001-03-01T00:00:00Z -> here P1Y == P365D

We are not sure either what the result of 2000-02-29 + P1Y should return. There are surely some other cases that we have overlooked and are ambiguous also.

Problem 2 :

* xs:duration +/- xs:duration *

It should also be possible to add and subtract durations, and return overflow errors if the partial values  (i.e. any one of Y, M, D, etc. components) evaluate to something negative. i.e. P1Y - P1D == error but P1Y1D - P1D = P1Y

Note that in this case addition does not cause any problem from the arithmetic point of view, but it is stated in F&O : 

"Operations on durations (including equality comparison, casting to string, and extraction of components) all treat the duration as normalized. This means that the seconds and minutes components will always be less than 60, the hours component less than 24, and the months component less than 12. Thus, for example, a duration of 120 seconds always gives the same result as a duration of two minutes." 

so maybe a overflow should also be generated if the result of the operation is beyond these boundaries.

Problem 3 :

* xs:dateTime – xs:dateTime = xs:duration *

The previous requirement causes a different problem, since xs:dayTimeDurations can have D components greater than 30.

Consider for instance op:subtract-dateTimes( 	$arg1 	 as xs:dateTime,$arg2 	 as xs:dateTime) as xs:dayTimeDuration? Given proposition 1, this operator should return a normalized (positive or negative) xs:duration + an anchor start value (for instance $arg1) 

i.e., the current example is : ‘op:subtract-dateTimes(xs:dateTime("2000-10-30T06:12:00"), xs:dateTime("1999-11-28T09:00:00Z")) returns an xs:dayTimeDuration value corresponding to 337 days, 2 hours and 12 minutes’
It should return a xs:duration("P11M1D2H12M") (since in the example the dynamic context provides a time zone value of -05:00) and the anchor value xs:dateTime("2000-10-30T06:12:00")

Our opinion:

All this takes a close looking into, but it seems possible to make some sound arithmetic out of all this, without introducing subtypes such as xs:yearMonthDuration and xs:dayTimeDuration.


Benjamin Nguyen & Tristan Allard
UVSQ
Comment 13 Michael Kay 2009-04-28 11:17:13 UTC
PROPOSAL (ACTION A-392-10):

(a) Define (duration * number) and (duration div number) to work on all durations, not only the two subtypes as at present. The semantics are defined by splitting the duration into a yMD and a dTD, then applying the current operator, then recombining the results.

The results may be a little idiosyncratic in the case where the number is not an integer, but it's perfectly well-defined and there are many cases where it's useful.

(b) Define (D +|- duration) for all durations (not only the two subtypes) where D is a date or dateTime. The semantics are defined by splitting duration into a yMD and a dTD and then taking (D +|- yMD +|- dTD). This is well-defined over all durations.

(c) Define (T +|- duration) where T is an xs:time for all durations (not only for dTD). The number of years/months in the duration is ignored, just as the number of days is currently ignored.

(d) Define (duration +|- duration) for all durations, but returning a dynamic error for certain combinations of operands. Specifically, the two durations are decomposed into yMD and dTD; the two components are independently added and subtracted; if the two partial-results have the same sign, they are combined together to form the result; if they have opposite sign, the result is a dynamic error.

(Note: there are a number of ways we could implement this proposal, depending how much we want to change the op: functions.)
Comment 14 Tristan Allard 2009-05-13 13:12:37 UTC
A minor note concerning Mike Kay's proposal:

> (b) Define (D +|- duration) for all durations (not only the two subtypes) where
> D is a date or dateTime. The semantics are defined by splitting duration into a
> yMD and a dTD and then taking (D +|- yMD +|- dTD). This is well-defined over
> all durations. 

The spec should warn the reader that ((D +|- yMD) +|- dTD) may give a result different from ((D +|- dTD) +|- yMD). 


Regards,
Tristan Allard, Bogdan Butnaru, Benjamin Nguyen
Comment 15 Michael Kay 2009-06-16 15:48:54 UTC
My current thinking on this bug, subject to WG approval, is to withdraw this bug report retaining the status quo in the spec. The discussion appears to reveal that doing anything in this area is complicated, and probably not worth the benefits.
Comment 16 Innovimax 2009-07-03 22:12:49 UTC
Might be a good use case for eXPath if withdrawn 
Comment 17 Michael Kay 2009-07-07 15:48:28 UTC
At the originator's suggestion, the WG agreed to close this as WONT FIX (the pain is greater than the gain...)