tolu / iso8601-duration Goto Github PK
View Code? Open in Web Editor NEWNode/Js-module for parsing and making sense of ISO8601-durations
Node/Js-module for parsing and making sense of ISO8601-durations
Parsing durations with significant millisecond accuracy (which do not appear to strictly follow the ISO8601 spec) returns incorrect results
E.g:-
Parse 'PT52M59.989333S' incorrectly returns a duration of :-
{"weeks":0,"years":0,"months":0,"days":0,"hours":0,"minutes":52,"seconds":0}
however Parse 'PT52M59.989S' correctly returns a duration of :-
{"weeks":0,"years":0,"months":0,"days":0,"hours":0,"minutes":52,"seconds":59.989}
Ideally the module should either correctly convert values that do not strictly conform to
the ISO8601 spec
const numbers = '\\d+(?:[\\.,]\\d+)?';
or it should throw an exception when a value with an unexpected/unconvertible format is provided.
During the last time change on 5 November, while using the toSeconds
method to parse durations, I noticed that it may return negative values when time changes from summer time to standard time even if the duration being parsed is supposed to be positive.
It looks like this happens because new Date().getTime()
is called in two independent locations. If the time differs between the two calls (for example during Daylight Saving Time changes) it will return an incorrect value.
parse('abc');
Throws error
TypeError: Cannot read property 'slice' of null
at parse (node_modules/iso8601-duration/lib/index.js:35:10)
Shouldn't throw a type error.
Add something like this: (From wikipedia article)
For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".
Date and time elements including their designator may be omitted if their value is zero, and lower-order elements may also be omitted for reduced precision. For example, "P23DT23H" and "P4Y" are both acceptable duration representations. However, at least one element must be present, thus "P" is not a valid representation for a duration of 0 seconds. "PT0S" or "P0D", however, are both valid and represent the same duration.
I think it would be useful to have a method similar to toSeconds
, but for converting a Duration
object to a ISO8601 duration string.
For example:
toString({
"weeks": 0,
"years": 3,
"months": 6,
"days": 4,
"hours": 12,
"minutes": 30,
"seconds": 5
})
// P3Y6M4DT12H30M5S
You have correctly allowed , as part of the number..
const numbers = '\\d+(?:[\\.,]\\d+)?'
but sadly, you are then straight up using parseFloat()
which treats "0,5"
as 0
You may need to do something such as
prev[objMap[idx]] = parseFloat(next ? next.replace(/,/g, '.') : next) || 0
Though, I will admit, not the best looking logic
It would be great to have a function that given an object, will create the iso duration string.
For example, an input of:
{ hours: 1 }
would return:
"P0Y0M0DT1H0M0S"
The Doc says Fractions are allowed on the smallest unit in the string, e.g. P0.5D or PT1.0001S but not PT0.5M0.1S.
However parse("P0.5D")
causes error
Fractions in Years, Months and Weeks also causes the same error.
My potential use case is to parse free trial periods for subscription IAP products on Google Play.
These are provided in ISO 8601 format. See docs.
When the trial period is et to 30 days, Google provides this string for the duration: P4W2D
. (4 weeks and 2 days = 30 days)
Parsing this string does not include the days in the result.
console.log('parse(`P4W2D`)', parse(`P4W2D`));
parse(`P4W2D`) { weeks: 4, years: 0, months: 0, days: 0, hours: 0, minutes: 0, seconds: 0 }
parse('PT-11H-11M')
returns 0 every time. Is it possible, somehow, to return negative hours and minutes response?
Certain instances of fractional time don't seem to compute properly when minutes are involved, for instance:
$ node
> var iso8601Duration = require("iso8601-duration");
undefined
> iso8601Duration.toSeconds(iso8601Duration.parse("PT0.5M"))
0 ===> expected 30
> iso8601Duration.toSeconds(iso8601Duration.parse('PT1H30M10.5S'))
5410.5
> iso8601Duration.toSeconds(iso8601Duration.parse("PT0H5M1.5S"))
301.5
> iso8601Duration.toSeconds(iso8601Duration.parse("PT1.5S"))
1.5
> iso8601Duration.toSeconds(iso8601Duration.parse("PT1.67S"))
1.67
> iso8601Duration.toSeconds(iso8601Duration.parse("PT0.67S"))
0.67
> iso8601Duration.toSeconds(iso8601Duration.parse("PT1.5M"))
60 ===> expected 90
Are my expectations here correct?
TypeScript has support for constructing string types using template strings (Template Literal Types). Those types could be used to construct a string type that allows only valid ISO8601-duration strings instead of any arbitrary string.
For example, something like this may work:
type Duration =
| `P${`${number}Y` | ''}${`${number}M` | ''}${`${number}D` | ''}T${`${number}H` | ''}${`${number}M` | ''}${`${number}S` | ''}`
| `P${number}W`;
// valid assignment
const valid: Duration = 'P1Y2M4DT20H44M12.67S';
// invalid assignment: '"test"' is not assignable to type 'Duration'
const invalid: Duration = 'test';
That being said, I'm not entirely sure if this would actually be useful, since in most use cases the duration strings come from external APIs and so are not typechecked at compilation time. What do you think?
Hi!
You have a function toSeconds
, I'd like to propose an inverse function:
fromSeconds: (seconds: number, startDate?: Date) => Duration
Hi there,
thank you very much for providing this library!
However, I noticed, that the regex pattern also matches expressions like P
or PT
.
According to Wikipedia, this is no valid duration:
However, at least one element must be present, thus "P" is not a valid representation for a duration of 0 seconds.
It would just be a helper function to consolidate some code
const expireAt = Date.now() + (toSeconds(parseDuration('PT1H')) * 1000);
const expireAt = Date.now() + parseDurationMs('PT1H');
Makes usage so much simpler.
https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html
nesh> const { parse } = require('iso8601-duration')
undefined
nesh> parse('P1111111111')
{ weeks: 0,
years: 0,
months: 0,
days: 0,
hours: 0,
minutes: 0,
seconds: 0 }
I am not sure if this is a bug or a feature that I don't understand. I get the duration of a year in seconds like this:
import { parse, toSeconds } from "iso8601-duration";
console.log(toSeconds(parse('P1Y'))) //31536000
And when I get 2 years in seconds, the value seems to be wrong:
import { parse, toSeconds } from "iso8601-duration";
console.log(toSeconds(parse('P2Y'))) //It returns 63158400, instead of 63072000
Why is that?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.