# Finding a future year in a cycle of years

I have a problem of finding a future year based upon a fixed past year. I can come to the correct answer if I use an if statement, but I feel this should be accomplished with one formula.

For example, let $$\text{CurrentYear} = 2018,\quad \text{cycleYears} = 3,\quad \text{baseYear} = 2015$$

With these values I can simply say $$\text{(mod(CurrentYear - baseYear), cycleYears) + CurrentYear}$$

and I get the expected answer of $2018$. Now, let $\text{baseYear} = 2014$ and get a value of $2019$, off by one. Simple, factor in the remainder to the above formula.

$$\text{(mod(CurrentYear - baseYear), cycleYears) + CurrentYear + mod(CurrentYear - baseYear)}$$

Now I get the expected answer of $2020$, and this tweak works for the base year of $2015$ as the modulus is zero.

Now, let $\text{baseYear} = 2016$ and the year with the first formula is 2020 (off by one) and with the second one is 2022 (skipped the current year in favor of the next cycle). The correct answer is 2019.

I can get this to work with an if of some sort, checking the modulus value, but I feel this should work without a logic branch.

Thoughts?

Update/Clarifications

I am trying to compute a series of years based upon an base year and how many years this date cycles.

A real-world example would be election years. For a US President, the baseYear could be any leap year, let's say 1976. We also know that that office is elected every 4 years. So, I could use this formula and find out that the next presidential election is in 2020. Like wise, a US Senator is on a 6 year cycle. Some senators could have a base year of 1974, so their next election would be this year in 2018.

• Just drop the $mod$ Commented Aug 22, 2018 at 19:03
• @OldPeter, OK, I tried it, but still not quite. It's fine for the 2018 example, but it doesn't work for the other 2. Plus, without using mod, it is even more off if say the base year is 2012 instead of 2015.
– Jim
Commented Aug 22, 2018 at 22:02
• It is not completely clear what you are trying to compute. Is it the function that can be defined as follows: "If baseYear is greater than or equal to currentYear return the base year; else add the minimum integer multiple of cycleYears to baseYear such that the sum is greater than or equal to currentYear, and return the sum"? Commented Aug 22, 2018 at 22:37
• Or if I say currentYear = 2018, baseYear = 2030, cycleYears = 5 should I get the result 2020? Commented Aug 22, 2018 at 22:38
• I'm not quite clear on what you're trying to compute either. "... and I get the expected answer of 2018." Why was 2018 your expected answer from the first example? Why is 2018 still the expected output even if you change the $\mathrm{baseYear}$? Commented Aug 23, 2018 at 3:27

To rephrase the question, you want to find the least $y$ satisfying $y \ge y_0$ and $y \equiv y_{base} \pmod \omega$. Here $y_0$ is the current year, $y_{base}$ is the base year, and $\omega$ is the cycle length.

Unfortunately this is hard to do with a conventional modulo operator and no case splits. The related problem of finding the least $y'$ such that $y' > y_0$ and $y' \equiv y_{base} \pmod \omega$ is solved with $$y' = y_0 + \omega - ((y_0 - y_{base}) \bmod \omega)$$ but if your modulo operator gives $0$ as a result instead of $\omega$ then it's arguable that the simplest expression for $y$ is $$y = \begin{cases}y_0 & \text{when } y_0 \equiv y_{base} \pmod \omega \\ y_0 + \omega - ((y_0 - y_{base}) \bmod \omega) & \text{otherwise} \end{cases}$$

I suppose that if you really want to avoid case splits you have $$y = y_0 + ((\omega - ((y_0 - y_{base}) \bmod \omega)) \bmod \omega)$$

• Yes, that seems to do the job. And yes, I was looking to avoid case splits. I am looking to add this to a SQL table as a calculated field along with the base year.
– Jim
Commented Aug 23, 2018 at 15:19
• Then I'll mention an implementation note. Many (not all - don't know about SQL variants) programming languages implement the modulo operation in a way which is inconsistent with the way it's used in number theory: specifically, they can give a negative result if one of the operands is negative. The double-mod here will be robust against that even in the case $y_{base} < y_0$, so that's a useful side-effect of using the double-mod instead of the case split. Commented Aug 23, 2018 at 15:31
• Good to know. And yes, Microsoft SQL Server can do that. I just ran Select 10 % 4, -10 % 4, 10 % -4 , -10 % -4 and the second and fourth one, with the first operand being negative gave a negative result. If only the second operand is negative, then the result is positive. I will check if this can happen in my actual use or if I need to wrap an abs() around it.
– Jim
Commented Aug 23, 2018 at 16:16
• Don't use abs! The correct way to bring a negative % result into range is to add the second operand. But it's not necessary anyway if you use the double-mod: I apologise if my comment has brought confusion where there was none (and see now that I typed $<$ where I should have typed $>$). Commented Aug 23, 2018 at 16:30