Generating dates between a start and end date

The task seemed easy enough: given a start and end date, generate all dates between them. I came up with code that works, but it feels hacky. For example, to find all dates between today, 2020-12-29, and January 6th next year, 2021-01-06, I would write:

between(0, inf, X),
Day is 29+X,
format_time(string(Date), "%F", date(2020, 12, Day)),
( Date @>= "2021-01-06" -> ! ; true )

What bothers me:

  • the inf in the between, this is begging for trouble?
  • the conditional. I actually got it right by trial and error, which means that I am not a good programmer, but could also mean that others might have trouble deciphering the meaning if they read the code. (comments might help)

The other approach was to do something like this:

date_time_stamp(date(2020, 12, 29), From),
date_time_stamp(date(2021, 1, 6), To),
Days_between is round((To - From) / (24 * 60 * 60)),
between(0, Days_between, X),
Day is 29 + X,
format_time(string(Date), "%F", date(2020, 12, Day))

… but I am not sure if this is an improvement.

Any idea how to make this cleaner or more readable? Any problems with any of the two approaches?


This is difficult because I don’t know how to easily calculate the number of days between two dates. I also don’t know if the calculation I do in the second example is always correct.

I think that pack(julian) is worth to try…

?- delta_time(2020-12-31,D,2021-2-1).
D = days(32).

Thank you!

Yes… I am still not super excited about using packs, which is my own problem.

Indeed packs have their limitation. This morning, installing pack(julian), I got a weird error message, and now I’m unsure about the status of the library. Doesn’t help too much that apparently the functionality is there…

What about this snippet?

:- module(datenum,
          [between_dates/3, date_tomorrow/2]).

between_dates(Start,Stop,Start) :-
    Start @=< Stop.
between_dates(Start,Stop,Date) :-
    Start @=< Stop,
    date_tomorrow(Start,Next),
    between_dates(Next,Stop,Date).

date_tomorrow(date(Y,M,D),Date) :-
    succ(D,T),
    date_time_stamp(date(Y,M,T,0,0,0,0,-,-),Stamp),
    stamp_date_time(Stamp,N,0),
    date_time_value(date,N,Date).

I’m suggesting this since too much naivety handling timestamps seems doomed to fail. Indeed I started date_tomorrow/2 adding 24 * 60 * 60 to the timestamp, but the outcome from stamp_date_time was 23:00 of the same day. Daylight saving rules…

1 Like