Closed StefanKarpinski closed 10 years ago
In general, I think this is the right thing to do, but note you still have the behavior like:
In [45]: [Date(2014,4,30):Month(1):Date(2015,4)]
Out [45]: 12-element Array{Date,1}:
2014-04-30
2014-05-30
2014-06-30
2014-07-30
2014-08-30
2014-09-30
2014-10-30
2014-11-30
2014-12-30
2015-01-30
2015-02-28
2015-03-30
So even though you started from April 30th (last day of the month), you don't get the last days of all months going forward. But then again, this is also matches exactly how we do Date-Month arithmetic anyway, so overall at least we're being consistent with this.
I'd still like to explore the idea of date-like objects representing intervals of time so that you would do this sort of thing by asking for the last day of each month – or the 30th day of each month, if that's what you want, which would then error out if any of the months you asked that of didn't have a 30th day.
You should dive into the adjusters.jl
file a little more; it's a higher-order programming approach to just this kind of thing. To get the last day of every month in the "adjusting" way would be as simple as:
In [3]: recur(x->x==lastdayofmonth(x),Date(2014):Date(2015))
Out [3]: 12-element Array{Date,1}:
2014-01-31
2014-02-28
2014-03-31
2014-04-30
2014-05-31
2014-06-30
2014-07-31
2014-08-31
2014-09-30
2014-10-31
2014-11-30
2014-12-31
Shouldn't we encourage this by not supporting the likely-to-be-wrong way of doing it?
The likely-to-be-wrong way being using ranges?
Well, ranges with ill-defined steps with respect the the endpoints, as in this case.
Should we formalize a relative-Date type with an expression constructor? For example,
RelDate( :( 1b+2w+m+y ) )
When applied on a date (with a holiday calendar), we get next biz day + 2 weeks, 1 month, and 1 year.
My motivation is that there are many more relative date expressions than day/ week/ month / year. For example you could use 'e' for end of month, 'a' for start of month, 'd' for day (ignore holiday), 'b' for same day or next business day (if landed on a holiday), 'p' for same day or previous business day (if landed on a holiday). 'w1' to 'w7' for the next weekday, and so on...
To be able to chain them would be very powerful. So you can express things like
Date(y, 5 ) + RelDate( :( e-w1) )
for Memorial Day, etc.
I haven't processed this idea fully, but using expressions like this strikes me as a bad idea.
@tonyhffong, please check out the adjusters.jl
code, you can accomplish everything you discussed plus much more (and a much better API). I really need to settle on some solid documentation for that, because I've had several comments of wanting to develop this and that and it can all be done through the adjuster interface. I'll bump the docs up on my list and maybe do a demo/blog post to share on the users forum.
@StefanKarpinski , I'm agnostic to using Expr vs String. I'm fine with just RelDate( "2w+1b" )
(if your "expression" means Expr). At the end of the day, each "letter" simply corresponds to a distinct Period type. So this proposal is really about a very compressed way of doing date math. @quinnj, I'll take a look at adjusters.jl.
Strings are only better if this is its own little mini language. Still not entirely sold on it though.
Happy to discuss pros and cons. For completeness, I can see the use case for date math requiring a union of holiday calendars so you are dealing with fairly long expressions like
[Date(2014,4,30):HolidayMod( [ cal1, cal2 ], Month(1)+EndOfMonth()+SameOrPreviousBDay() ):Date(2015,4)]
So a little DSL that shortens to something like:
Date(2014,4): RelDate( "1m+e+0p", [cal1, cal2] ): Date(2015,4)
may pay in terms of readability. The idea is similar to strftime, regex, printf, etc.
I would expect this to give me the last day of each month, which the other technique gives.