Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

How to convert a vague time specfier into a concrete timestamp

by chrestomanci (Priest)
on Sep 20, 2022 at 16:00 UTC ( #11147020=perlquestion: print w/replies, xml ) Need Help??

chrestomanci has asked for the wisdom of the Perl Monks concerning the following question:

Greetings wise brothers,

I am looking for ways to do what the user means, even when they are annoyingly vague about it.

Specifically I am looking to write a user friendly program that will accept a vague time specifications such as "now", "today", "5pm Friday" etc from a user and convert it into a timestamp, similar to how the unix at job scheduler does it.

This will be for an interactive program, so the date parser does not need to be perfect, but it would be nice if I could find a library that is contains more parsing logic than I will have time to write myself.

Any links? My google fu is failing me, mainly because I can't work out what search terms to use.

I found the at daemon source code, but the parser uses a ycc grammar that looks to tricky to port to perl in an afternoon!

Thanks.

  • Comment on How to convert a vague time specfier into a concrete timestamp

Replies are listed 'Best First'.
Re: How to convert a vague time specfier into a concrete timestamp
by roho (Chancellor) on Sep 21, 2022 at 05:02 UTC
    Check out "DateTime::Format::Natural". The following test code displays the translation of over 400 generic date/time expressions.

    #!/usr/bin/perl use strict; use warnings; use DateTime::Format::Natural; my $parser = DateTime::Format::Natural->new( time_zone => 'America/New +_York' ); my @date_keywords; test_date_keywords(); exit; sub test_date_keywords { load_date_keywords(); for (my $i = 0; $i <= $#date_keywords; $i++) { my $dt = $parser->parse_datetime($date_keywords[$i]); my @dt = $parser->parse_datetime_duration($date_keywords[$i]); if (!$parser->success) { warn $parser->error; exit; } if (@dt) { for (@dt) { print $_->strftime('%Y-%m-%d %H:%M:%S'), qq( - "$date_ +keywords[$i]"\n); } } else { print $dt->strftime('%Y-%m-%d %H:%M:%S'), qq( - "$date_key +words[$i]"\n); } } return; } sub load_date_keywords { @date_keywords = ('06:56:06 am','06:56:06 pm','1:00 on sun','1:00 +sun','10 days ago','10 hours ago','10 minutes ago','10 months ago','1 +0 seconds ago','10 weeks ago','10 years ago','100th day','12:14 AM',' +12:14 PM','1am on sun','1am sun','1pm on sun','1pm sun','2nd monday', +'4:20pm','4pm today','4pm tomorrow','4pm yesterday','4pm','4th februa +ry','5:30am','5am today','5am tomorrow','5am yesterday','5am','6 am', +'6:00 today','6:00 tomorrow','6:00 yesterday','8 pm','afternoon','eve +ning','friday 03:00 am','friday 03:00 pm','in 5 days','in 5 hours','i +n 5 minutes','in 5 months','in 5 seconds','in 5 weeks','in 5 years',' +last day','last friday','last hour','last june','last minute','last m +onth','last quarter','last second','last week wednesday','last week', +'last year','midnight','mon 2:35','morning','next day','next friday', +'next hour','next minute','next month','next october','next quarter', +'next second','next week wednesday','next week','next year','noon','n +ovember 3rd','now','saturday','sunday 11:00','sunday at 05:00 am','su +nday at 05:00 pm','this afternoon','this day','this evening','this fr +iday','this hour','this minute','this month','this morning','this qua +rter','this second','this week wednesday','this week','this year','th +ursday afternoon','thursday evening','thursday morning','today 02:32' +,'today 2:32am','today 2:32pm','today afternoon','today at 2:32 AM',' +today at 2:32 PM','today at 4:00','today at 6:45am','today at 6:45pm' +,'today at midnight','today at noon','today evening','today morning', +'today','tomorrow 02:32','tomorrow 2:32am','tomorrow 2:32pm','tomorro +w afternoon','tomorrow at 2:32 AM','tomorrow at 2:32 PM','tomorrow at + 4:00','tomorrow at 6:45am','tomorrow at 6:45pm','tomorrow at midnigh +t','tomorrow at noon','tomorrow evening','tomorrow morning','tomorrow +','tuesday last week','tuesday next week','tuesday this week','wednes +day 02:30am','wednesday 02:30pm','wednesday 14:30','wednesday at 02:3 +0am','wednesday at 02:30pm','wednesday at 14:30','yesterday 02:32','y +esterday 2:32am','yesterday 2:32pm','yesterday afternoon','yesterday +at 2:32 AM','yesterday at 2:32 PM','yesterday at 4:00','yesterday at +6:45am','yesterday at 6:45pm','yesterday at midnight','yesterday at n +oon','yesterday evening','yesterday morning','yesterday','1:00 last f +riday','1:00 next friday','1:00 this friday','10 hours before midnigh +t','10 hours before noon','10 minutes before midnight','10 minutes be +fore noon','10 seconds before midnight','10 seconds before noon','11 +january 2 years ago','11 january last year','11 january next year','1 +1 january this year','12th day last month','12th day next month','12t +h day this month','1am last friday','1am next friday','1am this frida +y','1pm last friday','1pm next friday','1pm this friday','1st day las +t year','1st day next year','1st day this year','1st tuesday last nov +ember','1st tuesday next november','1st tuesday this november','2 day +s before now','2 hours before now','2 minutes before now','2 months b +efore now','2 seconds before now','2 weeks before now','2 years befor +e now','2nd friday in august','3 hours after today','3 hours after to +morrow','3 hours after yesterday','3 minutes after today','3 minutes +after tomorrow','3 minutes after yesterday','3 seconds after today',' +3 seconds after tomorrow','3 seconds after yesterday','3rd wednesday +in november','4 days from now','4 hours from now','4 in the afternoon +','4 minutes from now','4 months from now','4 seconds from now','4 we +eks from now','4 years from now','4th day last week','5 am last monda +y','5 am next monday','5 am this monday','5 hours after midnight','5 +hours after noon','5 minutes after midnight','5 minutes after noon',' +5 pm last monday','5 pm next monday','5 pm this monday','5 seconds af +ter midnight','5 seconds after noon','6 hours before today','6 hours +before tomorrow','6 hours before yesterday','6 in the morning','6 min +utes before today','6 minutes before tomorrow','6 minutes before yest +erday','6 mondays from now','6 seconds before today','6 seconds befor +e tomorrow','6 seconds before yesterday','6th day last week','6th day + next week','6th day this week','8th month last year','8th month next + year','8th month this year','9 in the evening','beginning of last mo +nth','end of last month','final thursday in april','fri 3 months ago +at 5am','last friday at 20:00','last sunday at 21:45','last thursday +in april','last tuesday 11 am','last tuesday 11 pm','last wednesday 7 +am','last wednesday 7pm','midnight last friday','midnight next friday +','midnight this friday','monday 4 in the afternoon','monday 6 in the + morning','monday 9 in the evening','monday last week','next friday a +t 20:00','next tuesday 11 am','next tuesday 11 pm','next wednesday 7a +m','next wednesday 7pm','noon last friday','noon next friday','noon t +his friday','saturday 3 months ago at 17:00','saturday 3 months ago a +t 5:00am','saturday 3 months ago at 5:00pm','this friday at 20:00','t +his tuesday 11 am','this tuesday 11 pm','this wednesday 7am','this we +dnesday 7pm','today 5 days ago','today 5 hours ago','today 5 minutes +ago','today 5 months ago','today 5 seconds ago','today 5 weeks ago',' +today 5 years ago','today at 13:00','tomorrow 1 year ago','tomorrow 3 + days ago','tomorrow 3 hours ago','tomorrow 3 minutes ago','tomorrow +3 months ago','tomorrow 3 seconds ago','tomorrow 3 weeks ago','tomorr +ow 3 years ago','tomorrow at 13','wednesday 1 month ago at 8pm','yest +erday 7 days ago','yesterday 7 hours ago','yesterday 7 minutes ago',' +yesterday 7 months ago','yesterday 7 seconds ago','yesterday 7 weeks +ago','yesterday 7 years ago','yesterday at 13:00','1 April to 31 Augu +st','1/3 to 2/3','100th day to 200th','10th to 20th day','16:00 nov 6 + to 17:00','1999-12-31 to tomorrow','2/3 to in 1 week','2009-03-10 9: +00 to 11:00','21:00 to 22:00 mar 3','21:00 to mar 3 22:00','26 oct 10 +:00 am to 11:00 am','3/3 21:00 to in 5 days','30th to 31st dec','30th + to dec 31st','6am dec 5 to 7am','first day of 2009 to last day of 20 +09','first day of may to last day of may','first to last day of 2008' +,'first to last day of september','for 4 days','for 4 hours','for 4 m +inutes','for 4 months','for 4 seconds','for 4 weeks','for 4 years','j +an 1 to 2','may 2nd to 5th','monday to friday','now to 2010-01-01','- +5min','+2d','1/3 16:00','1/3','11 january','17:00','18 oct 17:00','18 + oct 5 am','18 oct 5 pm','18 oct 5am','18 oct 5pm','19:00 jul 1','200 +5','2010 october 28','2011-jan-04','20111018000000','2016-06-19T12:12 +:11','27/5/1979','3 jan 2000','3/1 16:00','3/1','3:20:00','4:00','7 a +m jul 1','7 pm jul 1','7am jul 1','7pm jul 1','dec 25','feb 28 3 am', +'feb 28 3 pm','feb 28 3:00','feb 28 3am','feb 28 3pm','february 14, 2 +004','jan 24, 2011 12:00','jan 24, 2011 12am','jan 24, 2011 12pm','ja +n 3 2010','january 11','march 1st 2009','march','may 27th','October 2 +006','1 hr ago','1 min ago','1 sec ago','1 yr ago','10 secs ago','3 h +rs ago','5 mins ago','7 yrs ago','final thurs in sep','thur','thurs', +'tues this week','tues','yesterday @ noon'); return; }

    "It's not how hard you work, it's how much you get done."

Re: How to convert a vague time specfier into a concrete timestamp
by isotope (Chaplain) on Sep 20, 2022 at 17:21 UTC
Re: How to convert a vague time specfier into a concrete timestamp
by perlsherpa (Initiate) on Sep 20, 2022 at 19:46 UTC
    Here's a good start using static words that do not require you to treat them as a DSL (domain specific language).
    # referred to as 'words2date.pl' below use strict; use warnings; use POSIX qw/strftime/; my $datewords = join q{ }, @ARGV; # Take "vague" words and convert them into a # date/time stamp, e.g.,: "now", "today", "5pm Friday" sub format_epoch { my $epoch = shift; # example, Tuesday, December 12, 1995 return strftime(qq{%A, %B %d, %Y},localtime($epoch)); } my $static_phrases = { now => sub { print format_epoch(time) }, today => sub { print format_epoch(time) }, tomorrow => sub { print format_epoch(time + 86400) }, yesterday => sub { print format_epoch(time - 86400) }, }; if ( defined $static_phrases->{$datewords} ) { $static_phrases->{$datewords}->(); } else { warn qq{[WARNING] I do not understand what you mean by, "$datewords" +\n}; }
    Example,
    shell> perl words2date.pl now
    Tuesday, September 20, 2022
    
    shell> perl words2date.pl today
    Tuesday, September 20, 2022
    
    shell> perl words2date.pl tomorrow
    Wednesday, September 21, 2022
    
    shell> perl words2date.pl yesterday
    Monday, September 19, 2022    
    
    The challenge is defining and implementing DSL, then translating that to the "date math" that will need.
    For example, SQL uses something very primative and structured when what you want is not NOW(), e.g.,
    SELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY)
    So my suggestion is to start with static word or phrases, then focus specifically on the challenge to develop a
    DSL (or implement a well established one) that can then be parsed and then used to get the numbers you need to
    perform the date math. Hope that helps.
Re: How to convert a vague time specfier into a concrete timestamp
by Marshall (Canon) on Sep 20, 2022 at 23:40 UTC
    Another approach would be to implement a GUI to make it easy for your users to be precise instead of "annoyingly vague".You can have options for: every other day, fortnight (2 weeks), 30 days, every month on this day, etc. I would not consider "at" as easy grammar for most of my "end users".
Re: How to convert a vague time specfier into a concrete timestamp
by awncorp (Acolyte) on Sep 21, 2022 at 19:31 UTC
Re: How to convert a vague time specfier into a concrete timestamp
by Anonymous Monk on Sep 25, 2022 at 01:29 UTC
    Several companies offer access to AI frameworks - Might be sort of overkill for asking for a time, but it is an option. Greetings

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11147020]
Approved by philipbailey
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2022-10-04 19:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My preferred way to holiday/vacation is:











    Results (18 votes). Check out past polls.

    Notices?