Reputation: 688
UPDATE The problem I was trying to solve required a bit more than the Date implementation, as it required a method to take into account both the post-1752 Gregorian and the pre-1752 Julian calendars' differing definitions of a leap year.
The following is my solution, which passed all my RSpecs and is a considerable improvement on the nested conditional I started with:
def leap_year?(year)
gregorian_year = true if year >= 1752
julian_year = true if year < 1752
gregorian_test = true if year % 4 == 0 && year % 100 != 0 || year % 400 == 0
julian_test = true if year % 4 == 0
case
when gregorian_year && gregorian_test
true
when julian_year && julian_test
true
else
false
end
end
ORIGINAL QUESTION
I wrote a simple, ugly nested conditional to achieve the following:
To achieve the following:
Return "true" if the year meets the following conditions:
I wrote an ugly nested conditional:
if year % 4 == 0
puts "Divisible by four"
if year % 100 == 0
puts "Century year"
if year % 400 == 0
puts "Quad-century year, leap year"
true
else
"Not a Quad-century year, not a leap year"
false
end
else
puts "Not a century year, leap year"
true
end
else
puts "Not divisible by four: not a leap year."
false
end
I tried to achieve the same with a case conditional, but it fails to detect the number 2016 as leap year:
case year
when (year % 4 == 0 && year % 100 != 0)
true
when year % 400
true
when year % 4 != 0
false
end
Two questions:
Upvotes: 1
Views: 882
Reputation: 5977
If you would like to determine if a given year is a leap year, that has already been implemented for you in the Date
class as Date#leap?
:
Date.leap?(2000)
#=> true
# Or, alternatively:
Date.gregorian_leap?(1900)
#=> false
Date.julian_leap?(1900)
#=> true
More info in the Ruby documentation: Date#leap?
If you would like to build it yourself regardless, this should work:
def leap_year?(year)
return false unless year % 4 == 0
return true unless year % 100 == 0
year % 400 == 0
end
leap_year?(2016)
#=> true
Upvotes: 3
Reputation: 54223
Remove the year
from case year
if your when
arguments are all boolean:
case
when (year % 4 == 0 && year % 100 != 0)
true
when year % 400 == 0
true
else
false
end
You can check it works :
def is_leap?(year)
case
when (year % 4 == 0 && year % 100 != 0)
true
when year % 400 == 0
true
else
false
end
end
require 'date'
p (0..2050).all?{|y| Date.leap?(y) == is_leap?(y)}
# true
This variant might be a bit more readable :
def is_leap?(year)
case
when year % 400 == 0
true
when year % 100 == 0
false
when year % 4 == 0
true
else
false
end
end
Finally, you could just write a single expression without any if
or case
:
year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
Upvotes: 3