-
Notifications
You must be signed in to change notification settings - Fork 721
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
Add fromISOTime, toISOTime and toMillis to Duration #803
Conversation
src/duration.js
Outdated
format = format.replace(/:/g, ""); | ||
} | ||
|
||
if (opts.suppressPrefix === "never" || opts.suppressPrefix === "auto" && (format === "hh" || format === "hhmm")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not against options like these, but we need to make sure they're consistent. We don't support these elsewhere, do we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, DateTime
has similar options, so I designed this to behave the same way.
See https://github.com/moment/luxon/blob/master/src/datetime.js#L1534
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically regarding the prefix suppression - this is unique to the time format:
As of ISO 8601-1:2019, the basic format is T[hh][mm][ss] and the extended format is T[hh]:[mm]:[ss]. Earlier versions omitted the T in both formats.
...
ISO 8601-1:2019 allows the T to be omitted in the extended format, as in "13:47:30", but only allows the T to be omitted in the basic format when there is no risk of ambiguity with date expressions.
So I made the default behavior here auto
, i.e. omit if possible - but if you're interacting with a system that always/never expects the prefix, this option allows you to override that behavior.
src/impl/regexParser.js
Outdated
@@ -118,6 +118,29 @@ function extractIANAZone(match, cursor) { | |||
return [{}, zone, cursor + 1]; | |||
} | |||
|
|||
// ISO time parsing | |||
|
|||
const isoTimeOnly = /^T?(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?$/; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't these identical to isoTimeBaseRegex
and extractISOTime
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are very similar, but not quite identical.
-
isoTimeOnly
includes the optionalT
prefix, and matches the beginning/end of the string -isoTimeBaseRegex
does not.This means
isoTimeBaseRegex
would match a value such asfoo00bar
, even though that's obviously not a valid Time value.
But I guess we could consider changing it to this, to reuse the existing regex:const isoTimeOnly = RegExp(`^T?${isoTimeBaseRegex.source}$`)
-
extractISOTimeOnly
preserves the precision of the value, by only setting the values that are actually specified in the string -isoTimeBaseRegex
always sets e.g.seconds
to 0, even if not specified.Either the seconds, or the minutes and seconds, may be omitted from the basic or extended time formats for greater brevity but decreased precision - https://en.wikipedia.org/wiki/ISO_8601#Times
One could of course argue
extractISOTime
should be fixed so it too preserves the precision - I'm just afraid that might be a breaking change, as code may have been written to expectseconds
in aDateTime
instance to always have a value.There's also a minor difference in the property names in the returned object - e.g.
seconds
instead ofsecond
. That's becauseDuration.fromObject
only accepts the plural version, which kinda makes sense, as it may represent arbitrary durations, and the singular name only makes sense when talking specifically about a time of day.
Hmm, looking at this again, I'd actually like to refactor it a little. |
@thomas-darling ok, let me know when you want me to take another look. I can spend some real time looking at this when it's ready; my comments so far were the result of only a very quick readthrough |
@icambron, will do 👍 |
test("DateTime#toISOTime({suppressSeconds: true}) will suppress milliseconds if they're zero", () => { | ||
expect(dt.set({ second: 0, millisecond: 0 }).toISOTime({ suppressSeconds: true })).toBe("09:23Z"); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed because it is identical to the test above
checkTime("11", { hours: 11, minutes: 0, seconds: 0 }); | ||
checkTime("T1122", { hours: 11, minutes: 22, seconds: 0 }); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This exactly matches how the time component of a date is parsed - including the, in my opinion, strange behavior where milliseconds are undefined if not specified, while the other values default to 0.
A general discussion could be had about whether defaulting to 0 is the correct behavior, as it means we actually loose the information about the precision of the value. That said, the need for that information is probably an uncommon edge case, and defaulting to 0 is very convenient, as it means users won't need null checks - so I'm ok with that.
However, I do think milliseconds should then also default to 0, both here and when parsing a date, as the current behavior is quite unexpected - especially since the typings for DateTime
claim the millisecond
property will always be a number...
Thoughts?
|
||
return value.toFormat(fmt); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is designed to behave just like the existing toISOTime()
in the DateTime
class - and that one has been extended to support adding the prefix, but is otherwise unchanged.
In my first implementation, the default was to automatically choose whether to add the prefix, depending on the format. However, I've since decided to drop that, and instead make it an explicit option, defaulting to false.
Technically, the 2019 version of the spec does require the prefix to be present for the basic format hhmm
, but the previous version didn't, so automatically adding it now would have been a breaking change.
Also, since the user already has to specify options to get the basic format, they might as well also specify if they want the prefix...
@icambron I think this is done now, so feel free to review when you have the time 🙂
|
@icambron, turns out I had a few bugs there - but should be all done now 🙂 |
I've justed "toied with the idea of doing" a merge request for a I am using
I am looking forward seeing the merge - request to be merged. |
Sorry for the long delay. Merged and will be released shortly. Thanks! |
This resolves #625, by adding a
fromISOTime
andtoISOTime
method to theDuration
class.The design of the methods is closely aligned with the design of similar, existing methods, such as
fromISO
andtoISO
.Additionally, since the
Duration
class has afromMillis
method, I've also added a correspondingtoMillis
method.The justification for this is, that having corresponding pairs of from/to methods, makes it easy to roundtrip a value in the same format, and that it aligns with the
DateTime
class, which already has both method.