In Julia, you may generate a date range by month like this:
julia> dr = Date(2014,1,29):Dates.Month(1):Date(2014,07,29)
Date("2014-01-29"):Month(1):Date("2014-07-29")
julia> collect(dr)
7-element Array{Date,1}:
2014-01-29
2014-02-28
2014-03-29
2014-04-29
2014-05-29
2014-06-29
2014-07-29
Date(2014,1,29)
is the start date, Dates.Month(1)
is the step, Date(2014,07,29)
is the end date.
Raku has a method later, but when used in custom generator, it lead to infinite range:
lazy my @dates = Date.new('2014-01-29'), Date.new('2014-02-28'), { $^a.later(:1month) } ... Date.new('2014-07-29')
If I use * >= Date.new('2014-07-29')
instead of Date.new('2014-07-29')
on the right of ... operator, it works:
lazy my @a = Date.new('2014-01-29'), Date.new('2014-02-28'), { $^a.later(:1month) } ... * >= Date.new('2014-07-29')
2014-01-29
2014-02-28
2014-03-28
2014-04-28
2014-05-28
2014-06-28
2014-07-28
2014-08-28
why the custom generator { $^a.later(:1month) }
in the { $^a.later(:1month) } ... Date.new('2014-07-29')
doesn't stop at 2014-07-29
and lead to infinite range?
As JJMerelo indicates in the comments, the way that the ...
operator works is to continue generating elements based on the left-hand-arguments until the right-hand-argument is (per smartmatching) exactly reached.
For example, if we made a sequence of multiples of 10s,
my @tens = 0, 10, 20 ... 95;
say @tens[10]; # 100
say @tens[11]; # 110
This is because not element of @tens
will actually be 95. To determine if an element is the final one, the smartmatch operator (~~
) is used. Smartmatching a DateTime
with another Datetime
returns true if the two represent the same time (which may be different nominal times because of timezones, etc).
For sequences, DateTime
is further complicated by the fact that .later
and .earlier
are not communative, so doing $date.later(:1month).later(:1month)
is not guaranteed to give the same result as $date.later(:2month)
.
The reason that * ≥ DateTime.new(…)
is different is that smartmatching for Callable
objects (which that technically is, it's whatever code equivalent to anon sub $dt { $dt ≥ DateTime.new(…) }
passes the left hand argument to the callable. If you're not 100% sure that a sequence will terminate by reaching an exact value, it's best to use the whatever code approach to ensure a value eventually matches.
Hmmm - for any kids out there trying this, there are some pitfalls to do with "what I mean"... for example when I try this
lazy my @b = Date.new('2014-01-31'), Date.new('2014-02-28'), { $^a.later(:1month) } ... * >= Date.new('2014-07-29')
I get this...
#(2014-01-31 2014-02-28 2014-03-28 ...)
But maybe I wanted the last day of each month, what if 2014 is a leap year, blah, blah
So if you want the last day (or last day -1), then there is also this handy method...
say Date.new('2015-11-24').last-date-in-month;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With