how can day/number go under each day? code below:
class month attr_reader :month, :year def initialize( month, year) @month = month @year = year end def month_names names_of_months = {1 => 'january', 2 => 'february', 3 => 'march', 4 => 'april', 5 => 'may', 6 => 'june', 7 => 'july', 8 => 'august', 9 => 'september', 10 => 'october', 11 => 'november', 12 => 'december'} return names_of_months[@month] end def length days_of_months = {1 => 31, 2 => 28, 3 => 31, 4 => 30, 5 => 31, 6 => 30, 7 => 31, 8 => 31, 9 => 30, 10 => 31, 11 => 30, 12 => 31} return days_of_months[@month] end def to_s weekdays = "su mo tu th fr sa" month = "#{month_names} #{year}" output = [ month.center(weekdays.size), weekdays ].join("\n") (1..length).each |day| output << day.to_s end output end end
below result.
january 2017 su mo tu th fr sa12345678910111213141516171819202122232425262728293031
as problem has been diagnosed, limit answer showing how make use of class date.
code
require 'date' day_width = 4 def calendar(year, month) title = "#{date::monthnames[month]}, #{year}".center(7*day_width) puts "\n#{title}" date::abbr_daynames.each { |s| print s.rjust(day_width) } puts arr = [*[' ']*date.new(year,month).wday, *1..days_in_month(year,month)] arr.each_slice(7) { |week| week.each { |d| print d.to_s.rjust(day_width) }; puts } end def days_in_month(year,month) (((month==12) ? date.new(year+1,1) : date.new(year,month+1)) - date.new(year,month)) end
[edit: in answer here, @spickerman expressed number of days in month thus: date.new(year,month,-1).day
. better,eh?]
examples
calendar(2015, 2) february, 2015 sun mon tue wed thu fri sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 calendar(2015, 4) april, 2015 sun mon tue wed thu fri sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 calendar(2016, 2) february, 2016 sun mon tue wed thu fri sat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
explanation
consider second example:
year = 2015 month = 4
first print title:
title = "#{date::monthnames[month]}, #{year}".center(7*day_width) #=> "april, 2015".center(28) #=> " april, 2015 " puts "\n#{title}"
next print day of week header:
date::abbr_daynames.each { |s| print s.rjust(day_width) } #=> ["sun", "mon", "tue", "wed", "thu", "fri", "sat"].each { |s| #=> print s.rjust(4) } # sun mon tue wed thu fri sat
for example, "sun".rjust(4)" #=> " sun"
.
now need print days in each week. i've done in 2 steps: first create array days printed, including 0-6
spaces in first week, print each group of 7 elements:
arr = [*[' ']*date.new(year,month).wday, *1..days_in_month(year,month)] #=> arr = [*[' ']*3, *1..30] #=> arr = [*[' ', ' ', ' '], *1..30] #=> [" ", " ", " ", 1, 2,..., 30]
we divide arr
groups of 7 , print each:
arr.each_slice(7) { |week| week.each { |d| print d.to_s.rjust(day_width) }; puts }
for example:
' '.to_s.d.to_s.rjust(4) #=> ' ' 10.to_s.rjust(4) #=> ' 10'
the number of days in april, 2015 computed follows:
(((month==12) ? date.new(year+1,1) : date.new(year,month+1))- date.new(year,month)) #=> (((4==12) ? date.new(2016,1) : date.new(2015,5))-date.new(2015,4) #=> date.new(2015,5) - date.new(2015,4) #=> #<date: 2015-05-01 ((2457144j,0s,0n),+0s,2299161j)> - #<date: 2015-04-01 ((2457114j,0s,0n),+0s,2299161j)> #=> (30/1), rational number equal 30