Skip to content
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

[Feature Request] TimeSpan.Dehumanize() #691

Open
pengowray opened this issue Mar 1, 2018 · 12 comments
Open

[Feature Request] TimeSpan.Dehumanize() #691

pengowray opened this issue Mar 1, 2018 · 12 comments

Comments

@pengowray
Copy link

pengowray commented Mar 1, 2018

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.

@clairernovotny
Copy link
Member

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

@pengowray
Copy link
Author

pengowray commented Mar 3, 2018

@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

@XtremeOwnageDotCom
Copy link

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

@XtremeOwnageDotCom
Copy link

XtremeOwnageDotCom commented Aug 22, 2018

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

@pengowray
Copy link
Author

pengowray commented Aug 25, 2018

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.

@XtremeOwnageDotCom
Copy link

XtremeOwnageDotCom commented Aug 25, 2018 via email

@XtremeOwnageDotCom
Copy link

discord-net/Discord.Net#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!

@pengowray
Copy link
Author

pengowray commented Nov 4, 2018

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.

@bernatgy
Copy link

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. 😢

@prodigy
Copy link

prodigy commented Jun 8, 2023

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.

@fdcastel
Copy link

fdcastel commented Aug 11, 2023

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.

@pengowray
Copy link
Author

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants