Easy way to determine leap year in ruby?
Use Date#leap?
.
now = DateTime.now
flag = Date.leap?( now.year )
e.g.
Date.leap?( 2018 ) # => false
Date.leap?( 2016 ) # => true
Leap Years. Program in Ruby. Can someone explain?
Let's go through the code line-by-line. I'll both explain what's going on and show how it could be improved.
puts 'Input a starting year:'
start_year = gets.chomp
It will be more convenient to make start_year
an integer so we don't have to keep converting between a string and an integer. We therefore should change the second line to
start_year = gets.to_i
If you examine the doc for String#to_i you will see that this is the same as
start_year = gets.chomp.to_i
Next,
puts 'Input an ending year:'
end_year = gets.to_i
puts ''
while start_year <= end_year
The last line requires that Ruby continue the while
loop as long as start_year <= end_year
is true
. She exits the loop when this expression becomes false
(when start_year == end_year + 1
). Notice the simplification in the this line and in the lines below.
if start_year % 400 == 0
puts start_year
If the year is divisible by 400
it is a leap year.
elsif start_year % 100 == 0
If the year is divisible by 100
, but not by 400
, it is not a leap year, so we do nothing, go to the end of the if/elsif/end clause and next execute start_year += 1
.
elsif start_year % 4 == 0
puts start_year
end
If the year is divisible by 4
, but not by 100
, is is a leap year. If start_year % 4 != 0
it is not a leap year, so we do not print it.
start_year += 1
which Ruby expands to start_year = start_year + 1
.
end
Return to the top of the loop and repeat.
Better
Here's a more Ruby-like way of writing that, converting the code to a method, using a single boolean expression and printing the return value of the method (an array of leap years).
def leap_years(start_year, end_year)
(start_year..end_year).select { |yr|
yr % 400 == 0 || (yr % 100 != 0 && yr % 4 == 0) }
end
puts 'Input a starting year:'
start_year = gets.to_i
puts 'Input an ending year:'
end_year = gets.to_i
p leap_years(start_year, end_year)
#=> [1904, 1908, 1912, 1916, 1920]
first_year..last_year
is a range (an instance of the class Range). Range
includes the module Enumerable
which provides it with the instance method Enumerable#select.
Best
The following would be easier way to obtain the leap years between two given years, by making use of the class method Date::leap?.
require 'date'
def leaps_between(first_year, last_year)
(first_year..last_year).select { |y| Date.leap?(y) }
end
leaps_between(2000, 2016)
#=> [2000, 2004, 2008, 2012, 2016]
leaps_between(1900, 1916)
#=> [1904, 1908, 1912, 1916]
Determine if a given year is a leap year
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
Implementing my own leap year class in ruby
The problem is Year.leap? should return true or false, not return a string, according to your tests.
class Year
def self.leap?(year)
(year % 400 == 0 && year % 100 == 0) || (year % 100 != 0 && year % 4 == 0)
end
end
Your tests will now pass.
The assert
is looking for a truthy response, refute
is looking for a falsy response.
We could've left the original code more intact, but saying...
if (condition_to_test) == true
return true
else
return false
end
is more succinctly rendered with just
condition_to_test
That will automatically return true
or false
as appropriate.
Rails Time.now.end_of_month not accounting for leap year
This is because the calculation computes the end of month for the current year and then adds 3 years.
(Time.now.beginning_of_month.to_date - 1.month)
= 28,Feb 2013. Add 3 years and you get 28, Feb 2016.
Try this instead -
((Time.now.beginning_of_month.to_date - 1.month) + 3.years).end_of_month
BTW, subtracting 2 months takes me to January (its still 31st March here)
Related Topics
Does Rails Come with a "Not Authorized" Exception
How to Sort a Ruby Hash Alphabetically by Keys
Provide Value for Self When Using Proc#Call
Rspec Any_Instance Deprecation: How to Fix It
Running Phantomjs from a Ruby on Rails Application
Why Don't Ruby Methods Have Lexical Scope
Problem When Installing Ruby 2.2.9 on MAC Big Sur M1
Why Is "❨╯°□°❩╯︵┻━┻" with Such an Encoding Used for a Method Name
Ruby: How to Calculate a Path Relative to Another One
Need Advice: Is This a Good Use Case for a 'Nosql' Database? If So, Which One
Single Occurrence Event with Ice_Cube Gem Using Start_Time and End_Time
How to Tell If I'm Running from Jruby VS. Ruby
Reinstall Every Gem for Each Ruby Version
Has Anyone Figured Out a Way to Run the Same Cucumber Scenario on Multiple Browsers/Web Drivers
How to Get Rspec to Run All Tests Nested Under a Folder
How to Print Something Without a New Line in Ruby
Rails Pass Params/Arguments to Activerecord Callback Function