How can i get the dates to fall on the perspective day?

与世无争的帅哥 提交于 2019-12-24 22:28:29

问题


How can i get the day/number go under each day? This is my 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 We Th Fr Sa"
    month    = "#{month_names} #{year}"
    output   = [
       month.center(weekdays.size),
       weekdays
    ].join("\n")
    (1..length).each do |day|
      output << day.to_s
    end
    output
  end
end

Below is my result.

January 2017
Su Mo Tu We Th Fr Sa12345678910111213141516171819202122232425262728293031

回答1:


As your problem has been diagnosed, I will limit my answer to showing how you could make use of the 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 his answer here, @spickerman expressed the number of days in the 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 the second example:

year = 2015
month = 4

First print the title:

title = "#{Date::MONTHNAMES[month]}, #{year}".center(7*DAY_WIDTH)
  #=> "April, 2015".center(28)
  #=> "        April, 2015         " 
puts "\n#{title}"

Next print the 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 we need to print the days in each week. I've done that in two steps: first create an array days to be printed, including 0-6 spaces in the first week, then print each group of seven elements:

  arr = [*[' ']*Date.new(year,month).wday, *1..days_in_month(year,month)]
    #=> arr = [*[' ']*3, *1..30]
    #=> arr = [*[' ', ' ', ' '], *1..30]
    #=> [" ", " ", " ", 1, 2,..., 30] 

We now divide arr into groups of seven and 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 is computed as 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), a rational number equal to 30



回答2:


You just forgot to add your spaces and newlines to the days. Try using something like this:

def to_s
    weekdays = "Su Mo Tu We Th Fr Sa"
    month    = "#{month_names} #{year}"

    output   = [
        month.center(weekdays.size),
        weekdays
    ].join("\n")
    output << "\n"

    i = 0
    (1..length).each do |day|
        i += 1
        output << day.to_s
        if day.to_s.length == 1
            output << '  '
        else
            output << ' '
        end
        if i == 7
            i = 0
            output << "\n"
        end
    end

    output
end

I added the first if statement to handle single length (1-9) dates' spacing, and the second to handle newlines (\n) after each week.

Running with:

Month.new(1, 2017).to_s

Your output will be:

    January 2017    
Su Mo Tu We Th Fr Sa
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 31 

Also, on a side note, don't forget about leap years (where February has 29 days).




回答3:


If you do not care about months that do not start on a Sunday (like you mentioned in this comment), you can just do this:

def to_s
  wdays  = "Su Mo Tu We Th Fr Sa"
  month  = "#{month_names} #{year}"
  output = [ month.center(wdays.size), wdays]

  (1..length).each_slice(7) do |week|
    output << week.map { |day| day.to_s.rjust(2) }.join(' ')
  end

  output.join("\n")
end

Use each_slice(7) to slice the array with all 31 days into sub arrays of 7 days (a week). Call map to transform each day in the sub array first into a string (to_s) and second ensure to handling alignment of single digits (rjust(2)). Join all days in a week with a single whitespace.



来源:https://stackoverflow.com/questions/29908876/how-can-i-get-the-dates-to-fall-on-the-perspective-day

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!