-
Notifications
You must be signed in to change notification settings - Fork 24
Duration: support negative durations by a '-' prefixing the ISO format #110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
apoelstra
wants to merge
1
commit into
GothenburgBitFactory:master
Choose a base branch
from
apoelstra:push-nommpskkwywq
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Currently in taskwarrior if you attempt to set a negative duration for a UDA, the UDA will appear to be set to PT0S (zero seconds). What is actually happening is a bit weird. Let's consider the example where the user types '-80s'. 1. First, Duration::parse_units will correctly read this as -80 seconds. 2. Then, Duration::formatISO will write this out as PT-1M-20S, which is what gets stored in the database. 3. Later, when the user attempts to read this value, Duration::parse will fail, and the default value of 0 will be output. In my view, we should either reject negative durations when the user first enters them, or this round-trip should succeed. I would kinda like to have negative durations, so this PR makes it succeed, by extending the ISO parser to allow negative entries for times. This approach has the benefit that users who have already accidentally put negative durations into their taskwarrior db will have these entries start working (though this may be perceived as a surprising/breaking change). It has the drawback that we're defining an ad-hoc extension to the ISO format and blessing it in our parser, making it a breaking change to revert this in the future. (Re "ad-hoc" -- I read through ISO 8601 and it does not allow this, or negative durations of any form for that matter. Also, our current code produces this output by using the modulo operator on negative numbers, which used to be implementation defined behavior) (though [this SE post](https://stackoverflow.com/questions/7594508/why-does-the-modulo-operator-result-in-negative-values) claims that C++11 defines it). It also has the drawback that users will see durations like PT-1H-56M-9S in their taskwarrior output, which to my eye looks like a bug, or at least an unintentionally exposed implementation detail. An alternative approach would be to extend the duration format by adding an optional +/- sign before the P. According to [this MDN page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration) this is defined by ECMAScript. The benefit here is: we're following a standard (assuming the MDN doc is correct); no existing timewarrior databases are likely to contain durations of this form, reducing the chances of "surprise" behavior changes; the resulting output looks much nicer. It's also easier to implement, though I need to modify both parse() and formatISO(). I have done it on a private branch -- let me know and I will close this PR and open one with this alternative approach.
apoelstra
added a commit
to apoelstra/gbf-libshared
that referenced
this pull request
Dec 27, 2025
…in ISO format According to [this MDN document](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration) there is an ECMAScript extension to ISO 8601 to allow signed durations by putting a + or - before the ISO duration format. Internally we support signed durations -- we will parse "-60w" or "-60min", which we store in a `time_t` (whose signedness is technically implementation defined, but which is signed on all major compilers). However, when formatting these as ISO 8601 we get get garbed output like PT-1H-56M-9S, which we cannot parse and probably neither can anything else. (Taskwarrior, when asked to assign a negative duration to a duration-typed UDA, will store this garbled output but then reproduce it as PT0S, an unfortunate user experience.) This PR updates `Duration::formatISO` to instead prepend a '-' before negative durations, and updates `Duration::parse_designated` to parse such things. Alternative to GothenburgBitFactory#110, which simply blesses the garbled format by extending the parser to support it.
Author
|
Actually I just opened an alternative -- #111. Please close at least one of these. |
apoelstra
added a commit
to apoelstra/gbf-libshared
that referenced
this pull request
Dec 27, 2025
…in ISO format According to [this MDN document](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration) there is an ECMAScript extension to ISO 8601 to allow signed durations by putting a + or - before the ISO duration format. Internally we support signed durations -- we will parse "-60w" or "-60min", which we store in a `time_t` (whose signedness is technically implementation defined, but which is signed on all major compilers). However, when formatting these as ISO 8601 we get get garbed output like PT-1H-56M-9S, which we cannot parse and probably neither can anything else. (Taskwarrior, when asked to assign a negative duration to a duration-typed UDA, will store this garbled output but then reproduce it as PT0S, an unfortunate user experience.) This PR updates `Duration::formatISO` to instead prepend a '-' before negative durations, and updates `Duration::parse_designated` to parse such things. Alternative to GothenburgBitFactory#110, which simply blesses the garbled format by extending the parser to support it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Currently in taskwarrior if you attempt to set a negative duration for a UDA, the UDA will appear to be set to PT0S (zero seconds). What is actually happening is a bit weird. Let's consider the example where the user types '-80s'.
In my view, we should either reject negative durations when the user first enters them, or this round-trip should succeed. I would kinda like to have negative durations, so this PR makes it succeed, by extending the ISO parser to allow negative entries for times.
This approach has the benefit that users who have already accidentally put negative durations into their taskwarrior db will have these entries start working (though this may be perceived as a surprising/breaking change). It has the drawback that we're defining an ad-hoc extension to the ISO format and blessing it in our parser, making it a breaking change to revert this in the future. (Re "ad-hoc" -- I read through ISO 8601 and it does not allow this, or negative durations of any form for that matter. Also, our current code produces this output by using the modulo operator on negative numbers, which used to be implementation defined behavior) (though this SE post claims that C++11 defines it) (I did not check -- reading ISO 8601 is one thing; the C++ standard is another :)).
It also has the drawback that users will see durations like PT-1H-56M-9S in their taskwarrior output, which to my eye looks like a bug, or at least an unintentionally exposed implementation detail.
An alternative approach would be to extend the duration format by adding an optional +/- sign before the P. According to this MDN page this is defined by ECMAScript (lol also not reading that standard). The benefit here is: we're following a standard (assuming the MDN doc is correct); no existing timewarrior databases are likely to contain durations of this form, reducing the chances of "surprise" behavior changes; the resulting output looks much nicer.
It's also easier to implement, though I need to modify both parse() and formatISO(). I have done it on a private branch -- let me know and I will close this PR and open one with this alternative approach.