Humanizer icon indicating copy to clipboard operation
Humanizer copied to clipboard

[Feature Request] TimeSpan.Dehumanize()

Open pengowray opened this issue 7 years ago • 12 comments

Yes, I know there's been some lengthy discussion about dehumanizing dates (#112). And the readme even states:

No dehumanization for dates as Humanize is a lossy transformation and the human friendly date is not reversible"

There's also already a couple of libraries that deal with ambiguous expressions such as "yesterday", "3 weeks ago", and "7 hours before tomorrow at midnight". e.g. nChronic and Microsoft LUIS.

However, I can't see any discussion about dehumanizing TimeSpans, which are much more straight forward. Even if the main focus here is on humanizing rather than the reverse, this kind of thing would be well suited to this library

TimeSpan

TimeSpans are much less ambiguous than dates. There also don't seem to be many other libraries that deal with them well. Here's some basic examples / semi-pseudocode tests for a TimeSpan dehumanizer:

var timeTest = new TimeSpan(3, 18, 0);
Assert.Equals(TimeSpan.Dehumanize("three hours and eighteen minutes"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("3 hours, 18 minutes"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("3:18 hours"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("3h18m"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("3h 18m"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("3.3hrs"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("3:18:00"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("3:18"), timeTest);
Assert.Equals(TimeSpan.Dehumanize("18:01", expectedUnits:minutes), new TimeSpan(0, 18, 01));

I think this kind of thing would be fairly straight forward and without ambiguity.

The other libraries I've found that deal with dehumanizing TimeSpans are:

  • Microsoft LUIS, e.g. builtin.datetimeV2.duration but it seems like it's overly complex and I'm guessing it's not open source. Also seems more focused on speech than text.
  • Exceptionless.DateTimeExtensions (Apache 2.0 licensed) has a parser that works as following: TimeSpan oneHour = TimeUnit.Parse("3h"); But would fail on all of the example strings I've given above as they are "complex".

TL;DR: Humanizer would be a good library to add a TimeSpan Dehumanizer to. I could be wrong, but I can't see anything overly complicated about it (unlike dehumanizing TimeDate text), as long as you stay away from accepting highly ambiguous inputs like "2 months" and stick to making it work as would be expected. I don't know much about what sort of things might trip up localization efforts though, but making it part of Humanizer would give a good chance for localization to occur.

I haven't (yet) poked around with the inner workers of Humanizer's parsers to see how easy it might be to add something like this, but thought I'd put it out there to see what interest was like.

pengowray avatar Mar 01 '18 06:03 pengowray

I'm curious about what context you would see this being useful?

clairernovotny avatar Mar 02 '18 17:03 clairernovotny

@onovotny My use case is a Discord (chat) bot which can act as a timer for "writing sprints" (a glorified 5 to 45 minute timer). So it accepts commands from members of chat.

Examples:

!sprint 15

Run a timer for 15 minutes.

!sprint 1000s

Run a timer for 1000 seconds.

image

This works here via DateTimeExtensions (mentioned in OP).

Ideally though...

But ideally a TimeSpan Dehumanizer would accept more arbitrary input. (These all fail to be parsed with DateTimeExtensions)

!sprint 12m 30s

This is a "complex" example (contains two units).

!sprint 0.25 hrs

This fails for multiple reasons: floating point, space, and odd spelling of hours. But shouldn't be difficult to make a dehumanizer for.

!sprint 15:10

Correctly treated as 15:10:00 (15h 10m) by built-in TimeSpan.Parse(), however an ideal parser should optionally treat it as 00:15:10 (15m 10s) when so configured.

!sprint twenty minutes

I was thinking Humanizer could already roundtrip numbers-to-words, but I just realized it only does this for Roman numerals, so maybe forget about this for now.

Conclusion

It's not 100% required feature, but I was surprised that there wasn't a library that enabled this kind of TimeSpan text parsing already (that I can find)

So basically, the use case is for entering a length of time for a timer where only text input is available, and the users are generally not be technical and have a low tolerance for failure (every failed attempt is seen by all members of the chat). Also, everyone likes a bot that can handle whatever is thrown at it.

More generally, I'd imagine this sort of function would also be useful anywhere users need to enter a time period as text, including: web forms, command line arguments, unit conversion calculators, text-based bots, and intelligent personal assistant services.

Edit: or it could be used in some hyper-advanced futuristic kid-friendly intellisense (excuse the crude mockup): image

pengowray avatar Mar 03 '18 02:03 pengowray

I will +1 this feature, for nearly the exact same use-case (Discord Bot)

XtremeOwnageDotCom avatar Aug 22 '18 17:08 XtremeOwnageDotCom

However, I will also note, The discord.net library already has built in support for this, using the TimeSpan type converter. https://github.com/RogueException/Discord.Net

https://discord.foxbot.me/docs/guides/commands/commands.html#type-readers

Specific type read module:

https://github.com/RogueException/Discord.Net/blob/dev/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs

XtremeOwnageDotCom avatar Aug 22 '18 17:08 XtremeOwnageDotCom

I had a go at creating this a while ago but never got around to polishing it up to share. I'll upload it as a separate github project when I get a chance. It allows inputs like "3m20s" or "3 min 20.5secs" or "3:00:10" etc and most of the examples from above. (It does not accept word input like "three hours and eighteen minutes" though)

I didn't know about Discord.Net's parser. I'll put in some tests to check mine is compatible with everything it accepts too.

I'll try to upload it during the week.

pengowray avatar Aug 25 '18 11:08 pengowray

I created a pull request for discord.net's version to fall back and use the built in parse method which helps alot.

It's not perfect, but, it understands... 1:10:00, 6d, 10m, 3s, etc....

On Sat, Aug 25, 2018, 6:26 AM Peter Halasz [email protected] wrote:

I had a go at creating this a while ago but never got around to polishing it up to share. I'll upload it as a separate github project when I get a chance. It allows inputs like "3m20s" or "3 min 20.5secs" or "3:00:10" etc.

I didn't know about Discord.Net's parser. I'll put in some tests to check mine is compatible with everything it accepts too.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Humanizr/Humanizer/issues/691#issuecomment-415962811, or mute the thread https://github.com/notifications/unsubscribe-auth/AFBNjxLCSwVA-JiqkGi7cdInXgiu35Ugks5uUTRngaJpZM4SX1Vi .

XtremeOwnageDotCom avatar Aug 25 '18 12:08 XtremeOwnageDotCom

https://github.com/RogueException/Discord.Net/pull/1131

So, to summarize, the discord.net version, will soon just be mostly utilizing the builtin timespan.parse methods.

It would be really great for humanizer to support this feature!

XtremeOwnageDotCom avatar Aug 27 '18 12:08 XtremeOwnageDotCom

Okay, here's my TimeSpanParser:

https://github.com/quole/TimeSpanParser

It doesn't parse "three hours and eighteen minutes" but it will do every other example.

pengowray avatar Nov 04 '18 21:11 pengowray

I'd like to see something like this as well... My use case is the following;

I'm trying to achieve user friendly configuration file for one of my app's timer based features. I was already using Humanizer to save a default in the format "x minutes, y seconds", by the time I noticed there's no Dehumanize for those values. One would expect something at least for this default format. 😢

bernatgy avatar Feb 21 '21 13:02 bernatgy

I support this as well, my use case is configuration of an application. As a TimeSpan cannot properly and reliable contain a span of months, but a string like "3 months" can, I would like to request this as a feature - together with a starting point from a given date. In that case you can correctly "dehumanize" the string "3 months" to a specific amount of days.

prodigy avatar Jun 08 '23 07:06 prodigy

I have a similar need for configuration files.

Instead of

timeout: 00:00:00.050

I could use

timeout: 50ms

or

timeout: 50 milliseconds

I believe HomeAssistant uses a similar format for user-configurable time intervals.

fdcastel avatar Aug 11 '23 20:08 fdcastel

@fdcastel TimeSpanParser will parse all those values to a TimeSpan. e.g. TimeSpanParser.Parse("50 milliseconds")

Note: TimeSpanParser only does English, and it will not do the relative dates mentioned by others such as "3 months from today" (though it will handle the unambiguous "0 months"). I've considered adding relative dates but I don't personally have a need for them.

I'd still love if Humanizer added this functionality. I have a lot of unit tests you guys could use. They were more comprehensive than Microsoft's and I even found a bug in Microsoft's TimeSpan.Parse code that I got patched.

pengowray avatar Aug 12 '23 12:08 pengowray