www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Date range iteration

reply Jordan Wilson <wilsonjord gmail.com> writes:
I wanted to iterate through a date range, so I initially tried:
iota(Date(2016,1,1),Date(2018,1,1),dur!"days"(1));

That wouldn't compile, which is fair enough I guess.

So I tried a for loop:
for (auto i = Date(2016,1,1); i < Date(2018,1,1); 
i+=dur!"days"(1)){}

That seemed to work fine, but I remember reading "for loops are 
bad" somewhere. So I looked for a range type mechanism, and I 
think it's this:
foreach (i; Interval!Date 
(Date(2016,1,1),Date(2018,1,1)).fwdRange ( (a) { return 
a+dur!"days"(1); })){}

My question is if the third way is the proper way of stepping 
through a period of time? It just seems quite complicated to me.

Thanks,

Jordan
Mar 11 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, March 12, 2018 02:11:49 Jordan Wilson via Digitalmars-d-learn 
wrote:
 I wanted to iterate through a date range, so I initially tried:
 iota(Date(2016,1,1),Date(2018,1,1),dur!"days"(1));

 That wouldn't compile, which is fair enough I guess.
Maybe iota should be made to work, but as present, it basically wants all three of the types it's given to be the same or implicitly convertible to a single type. It can't handle the step being a completely different type.
 So I tried a for loop:
 for (auto i = Date(2016,1,1); i < Date(2018,1,1);
 i+=dur!"days"(1)){}

 That seemed to work fine, but I remember reading "for loops are
 bad" somewhere.
for loops are just fine - especially if you're just going to loop through all the values and do something to them - but if you have a range, it's a lot more flexible.
 So I looked for a range type mechanism, and I
 think it's this:
 foreach (i; Interval!Date
 (Date(2016,1,1),Date(2018,1,1)).fwdRange ( (a) { return
 a+dur!"days"(1); })){}

 My question is if the third way is the proper way of stepping
 through a period of time? It just seems quite complicated to me.
Well, honestly, the range support in std.datetime isn't very good. The core problem that overcomplicates it is that the Interval needs to know which direction you want to iterate in, and then the helper functions tend to need to know it too in order to work properly. Also, the time point type being used also tends to get duplicated a fair bit. So, you end up with annoyingly repetitive code. The helper function intended for this use case is https://dlang.org/phobos/std_datetime_interval.html#everyDuration So, you'd get something more like auto interval = Interval!Date(Date(2016, 1, 1), Date(2018, 1, 1)); auto range = interval.fwdRange(everyDuration!Date(days(1))); But if you're just going to use the range in a foreach loop, then you might as well just use a for loop. All of this extra machinery only really starts being valuable when you start feeding the ranges into range-based functions. For a simple loop, it's overkill. - Jonathan M Davis
Mar 11 2018
parent Jordan Wilson <wilsonjord gmail.com> writes:
On Monday, 12 March 2018 at 02:49:34 UTC, Jonathan M Davis wrote:
 On Monday, March 12, 2018 02:11:49 Jordan Wilson via 
 Digitalmars-d-learn wrote:
 [...]
Maybe iota should be made to work, but as present, it basically wants all three of the types it's given to be the same or implicitly convertible to a single type. It can't handle the step being a completely different type. [...]
Yes I agree, a for loop for simple iteration is fine, but I'm sure there are cases where a date range would be quite useful, so the everyDuration tip is great, thanks! Jordan
Mar 12 2018