I currently have this monstrosity:
next_period = (((current_month + tax_period_months)-1) % 12) + 1
I want to get the month that is tax_period_months
after the current month.
E.g. if tax_period_months=3
, and current_month=09
then next_period=12
This works, but has that horrible -1 +1
to stop month 12
becoming 0
Any alternatives?
3 Answers 3
If that really is all you need to calculate, then it's not too bad.
However, I suspect that you have other date calculations happening in your application. In that case, why not take advantage of Ruby's Date
class? The >>
operator adds months.
require 'date'
next_period = (Date.today >> tax_period_months).month
-
1\$\begingroup\$ @tokland No, the
+
operator treats its second operand as the number of days to add, whereas the>>
operator treats its second operand as the number of months. \$\endgroup\$200_success– 200_success2016年09月05日 07:49:12 +00:00Commented Sep 5, 2016 at 7:49 -
\$\begingroup\$ @tokland Where do you get the
.months
extension method from? I get the error:NoMethodError: undefined method `months' for 2:Fixnum
. \$\endgroup\$200_success– 200_success2016年09月05日 07:54:38 +00:00Commented Sep 5, 2016 at 7:54 -
\$\begingroup\$ ruby-doc.org/stdlib-2.3.1/libdoc/date/rdoc/… \$\endgroup\$Ram on Rails– Ram on Rails2016年09月07日 20:56:26 +00:00Commented Sep 7, 2016 at 20:56
The purpose of the +1/-1
is just to cope with the fact that december gives 0
as result. But it's not entirely apparent that it's it purpose.
On the other side there is a ruby native method Integer#nonzero?
that returns the number itself when it's not zero, and nil
when it's zero.
This way it's made much more evident that we are dealing with a "we didn't expect zero" edge condition - in a way that -1/+1
does not convey.
next_period = ((current_month + tax_period_months) % 12).nonzero? || 12
Note that this does not require any dependency, ActiveSupport or what else.
I ended up doing this
next_period = current_month + tax_period_months
next_period -= 12 if next_period > 12
Not the fanciest but easier to read.
I'll accept @200_success as the top answer because it takes advantage of the Date
class, which will handle year changes, etc. (even though it didn't really work for my context).
-
\$\begingroup\$ I'm curious... why didn't it work? \$\endgroup\$200_success– 200_success2016年09月06日 21:53:48 +00:00Commented Sep 6, 2016 at 21:53
-
\$\begingroup\$ It was in the middle of a bunch of code dealing with periods (e.g. find the first day of the period which the calculated date lies in), and it was already constructed to use months separately to entire dates. I was adding a few changes, but the rest was already working ok. \$\endgroup\$Mirror318– Mirror3182016年09月06日 23:29:19 +00:00Commented Sep 6, 2016 at 23:29
-
\$\begingroup\$ This is much easier to read. \$\endgroup\$Wayne Conrad– Wayne Conrad2016年09月10日 09:45:27 +00:00Commented Sep 10, 2016 at 9:45
-1 +1
is pretty slick once explained in a comment. Also, I honestly don't know what you would do to make it better. You need to mapcurrent_month + tax_period_months
to $$\mathbb{Z}_{11}$$ and then increment everything by one. It would probably have to be a two step process that would require subtracting then adding 1. \$\endgroup\$-1+1
, but my personal philosophy is that code that doesn't need comments is easier maintained and therefore more valuable than code that makes sense only once you read the comments. \$\endgroup\$