stsc / DateTime-Format-Natural

Parse informal natural language date/time strings
5 stars 5 forks source link

demand_future not working for method count_weekday #16

Closed joernclausen closed 2 years ago

joernclausen commented 2 years ago

I would like to use this package to calculate patch dates in advance, i.e. expressions like "next 2nd Tuesday". This does not currently work, as demonstrated by this script:

#!/usr/bin/env perl

use strict;
use DateTime;
use DateTime::Format::Natural;

foreach my $day (1..30) {

  my $bd = DateTime->new(year => 2022,
                         month => 06,
                         day => $day);

  print $bd->strftime('%Y-%m-%d (%a)'),":  ";

  my $parser = DateTime::Format::Natural->new(datetime => $bd,
                                              demand_future => 1);

  my $dt = $parser->parse_datetime('2nd Tuesday');
  print $dt->strftime('%Y-%m-%d (%a)'),"  ";
  my $dt = $parser->parse_datetime('3rd Tuesday');
  print $dt->strftime('%Y-%m-%d (%a)'),"  ";
  my $dt = $parser->parse_datetime('4th Tuesday');
  print $dt->strftime('%Y-%m-%d (%a)'),"  ";
  my $dt = $parser->parse_datetime('4th Tuesday');
  $dt->add(days => 1);
  print $dt->strftime('%Y-%m-%d (%a)'),"\n";

}

which produces this output:

2022-06-01 (Wed):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-02 (Thu):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-03 (Fri):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-04 (Sat):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-05 (Sun):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-06 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-07 (Tue):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-08 (Wed):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-09 (Thu):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-10 (Fri):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-11 (Sat):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-12 (Sun):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-13 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-14 (Tue):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-15 (Wed):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-16 (Thu):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-17 (Fri):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-18 (Sat):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-19 (Sun):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-20 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-21 (Tue):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-22 (Wed):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-23 (Thu):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-24 (Fri):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-25 (Sat):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-26 (Sun):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-27 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-28 (Tue):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-29 (Wed):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-30 (Thu):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)

Starting wth 2022-06-15, the next 2nd Tuesday should be 2022-07-12, and so on.

stsc commented 2 years ago

Attached a preliminary patch which handles the case "$day $weekday".

I'm aware that there are other potential date/time strings which are not covered by this patch. Let me know if it goes in the right direction for you.

Thanks,

dtfn.diff.txt

joernclausen commented 2 years ago

Thanks for looking into this. Some results are better. The pattern of misses is interesting, though:

2022-06-01 (Wed):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-02 (Thu):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-03 (Fri):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-04 (Sat):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-05 (Sun):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-06 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-07 (Tue):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-08 (Wed):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-09 (Thu):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-10 (Fri):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-11 (Sat):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-12 (Sun):  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-13 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-14 (Tue):  2022-07-12 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-15 (Wed):  2022-07-12 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-16 (Thu):  2022-07-12 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-17 (Fri):  2022-07-12 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-18 (Sat):  2022-07-12 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-19 (Sun):  2022-07-12 (Tue)  2022-06-28 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-20 (Mon):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-21 (Tue):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-22 (Wed):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-23 (Thu):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-24 (Fri):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-25 (Sat):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-26 (Sun):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-05 (Tue)  2022-07-06 (Wed)
2022-06-27 (Mon):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-28 (Tue):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-26 (Tue)  2022-07-27 (Wed)
2022-06-29 (Wed):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-26 (Tue)  2022-07-27 (Wed)
2022-06-30 (Thu):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-26 (Tue)  2022-07-27 (Wed)

My expectation would be

stsc commented 2 years ago

The cause of the odd failures probably was the subsequent elsif statement

elsif ($token_contains->('weekdays_all') ..

which advanced the day by 7 days also whenever an expression containing a day and weekday failed to satisfy the condition

($self->{Demand_future} && $self->{datetime}->day <= $now->day)

above.

Once again, let me know, if it works for you :-).

dtfn.diff.txt

joernclausen commented 2 years ago

Spot on! I changed my script from demand_future to prefer_future (as this makes more sense for my use case), and now I get

2022-06-01 (Wed):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-02 (Thu):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-03 (Fri):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-04 (Sat):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-05 (Sun):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-06 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-07 (Tue):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-08 (Wed):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-09 (Thu):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-10 (Fri):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-11 (Sat):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-12 (Sun):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-13 (Mon):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-14 (Tue):  2022-06-14 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-15 (Wed):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-16 (Thu):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-17 (Fri):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-18 (Sat):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-19 (Sun):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-20 (Mon):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-21 (Tue):  2022-07-12 (Tue)  2022-06-21 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-22 (Wed):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-23 (Thu):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-24 (Fri):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-25 (Sat):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-26 (Sun):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-27 (Mon):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-28 (Tue):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-06-28 (Tue)  2022-06-29 (Wed)
2022-06-29 (Wed):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-26 (Tue)  2022-07-27 (Wed)
2022-06-30 (Thu):  2022-07-12 (Tue)  2022-07-19 (Tue)  2022-07-26 (Tue)  2022-07-27 (Wed)

which is exactly what I would expect! demand_future also works as expected, BTW :)

Thanks a lot for fixing/enhancing your module so fast.

stsc commented 2 years ago

I'll merge those changes and release a new version with some tests hopefully soonish.

stsc commented 2 years ago

DateTime::Format::Natural v1.12_01 has been released to CPAN.

stsc commented 2 years ago

Stable release v1.13, closing.