4
\$\begingroup\$

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?

200_success
146k22 gold badges190 silver badges479 bronze badges
asked Sep 5, 2016 at 4:38
\$\endgroup\$
4
  • 1
    \$\begingroup\$ I would argue the -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 map current_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\$ Commented Sep 5, 2016 at 5:55
  • \$\begingroup\$ @Dair: You probably meant \$ \mathbb{Z}_{12} \$. \$\endgroup\$ Commented Sep 5, 2016 at 6:13
  • \$\begingroup\$ Is that a RoR project? \$\endgroup\$ Commented Sep 5, 2016 at 7:57
  • 1
    \$\begingroup\$ @tokland yes it's Rails, @Dair I don't mind using -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\$ Commented Sep 6, 2016 at 0:12

3 Answers 3

6
\$\begingroup\$

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
answered Sep 5, 2016 at 6:37
\$\endgroup\$
3
  • 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\$ Commented 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\$ Commented Sep 5, 2016 at 7:54
  • \$\begingroup\$ ruby-doc.org/stdlib-2.3.1/libdoc/date/rdoc/… \$\endgroup\$ Commented Sep 7, 2016 at 20:56
4
\$\begingroup\$

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.

answered Sep 6, 2016 at 15:10
\$\endgroup\$
0
1
\$\begingroup\$

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).

answered Sep 6, 2016 at 21:48
\$\endgroup\$
3
  • \$\begingroup\$ I'm curious... why didn't it work? \$\endgroup\$ Commented 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\$ Commented Sep 6, 2016 at 23:29
  • \$\begingroup\$ This is much easier to read. \$\endgroup\$ Commented Sep 10, 2016 at 9:45

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.