質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

rubyで一ヶ月間の日付と曜日を出力したい。

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 1,651

yoshimitsu41

score 30

ruby初心者です。

やりたいことの理想形を書きます。
例えば…

ステップ1
make_day.rbというファイルを作っTerminalで実行すると
「西暦を入力して下さい。」
と出てきて「2017」と入力。

ステップ2
「月を入力して下さい」
とでてきて「10」と入力

すると
10/01日曜日
10/02月曜日
10/03火曜日
10/04水曜日
10/05木曜日
10/06金曜日
10/07土曜日
以下31日まで続く…。

というプログラムを作りたいです。

さらに
日曜日と土曜日だけ
10/01日曜日(休)
10/07土曜日(休)

といったふうに出るのが一番の理想です。

素人なりに調べて作ったのが下記でここからどのように発展させて作っていけば良いのかわかりません。
※そもそも動きませんでしたが…。

require 'date'
puts "年を入力してください:"
year = gets.to_i
puts "月を入力してください:"
month = gets.to_i
puts "日を入力してください:"
day = gets.to_i

d = Date.new(year, month, day)
week = %w(日 月 火 水 木 金 土 日)[d.cwday]


while day < 31
puts "#{year}#{month}#{day}日は#{week}曜日です"
day += 1
week += 1
end

お詳しい方ご教授お願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+3

問題点がいくつかあります。

 一つ目

まずそのままのコードで動かそうとするとweek += 1でエラーが出ているのがわかると思います。
エラーメッセージ:test.rb:16:in '+': no implicit conversion of Fixnum into String (TypeError) from test.rb:16:in '<main>'

dayには10行目で入れられた曜日の名前が入っています。
そこに数字である1を足そうとするとStringとFixnumを足すことになるのでエラーが起きます。

 二つめ

一ヶ月の日数は月によって違うので31にしてしまうと2月とかがうまく行かなくなってしまいます。
while文を回すには何月なので一ヶ月は何日という情報が必要になってきます。なので普通にdayを加算していくとifなどで分岐処理を書く必要が出てしまいめんどくさいです。

そこで、Dateクラスには便利なものがあって、dateクラスのメソッドのnextを叩くと次の日の情報に更新してくれます。

 三つめ

weekをに代入している部分って何をしているかわかりにくいと思います。
week = %w(日 月 火 水 木 金 土 日)[d.cwday]が何をしているかというと

%w(日 月 火 水 木 金 土 日)配列を作る
[d.cwday]その日が何曜日かを調べて配列からとってくる

と言う風になっていて

%W()は配列を作るメソッドで、配列の要素をスペースで並べる

d.cwdayは月〜日曜日を1〜7で表した数字を教えてくれる

なのでやっていることは以下と同じです。

week_name = ["日", "月", "火", "水", "木", "金", "土", "日"]
week = week_name[d.cwday]

またここで二つめと関わってくるのですが、一番最初のコードのようにweekを一回とってしまうと次の曜日っていうのが難しいので上のコードのようにweek_nameとweekで分けておいたほうがいいです。

ちなみにですが、cwdayは月から日を1~7なので配列からとってくる場合、一番最初の要素に空きが出てしまい、今回の場合日が二つあるみたいな状況になってしまいます。
そこで同じようなやつにwdayっていうのがあってこっちは日から土を0~6でとってくるので今回みたいな配列にアクセスするときには使いやすいです。

 コード

以上のことと本来実装したかったものをまとめて僕なりに書いてみました。

require 'date'
puts "年を入力してください:"
year = gets.to_i
puts "月を入力してください:"
month = gets.to_i

d = Date.new(year, month, 1)

week_name = %w[日 月 火 水 木 金 土]

while d.month == month // 入力された月を超えたらやめる
    str = "#{d.month}/#{d.day}#{week_name[d.wday]}曜日"
    // 土か日曜日だったら(休)をつける
    if d.wday == 0 || d.wday == 6
        str += "(休)"
    end
    puts str

    d = d.next
end
 変更点
  • 入力を月までにしました
  • Dateのdにはその月の情報をとってきたいので、1日にしてしまいます
  • while文の条件は入力された月と進めていった月が等しいにしています
  • if文でwdayが0か6(土か日曜日)だったらの時の処理をつけています

以上でどうでしょうか?

 おまけ

もっと短くすることはできますので短くしてみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/28 10:54

    非常に細かく解説して頂きありがとうございます!思った通りの動きが出来ました!wday知らなかったです。本当にありがとうございました!精進します。

    キャンセル

+2

おもしろそうなので書いてみました

「こういう書き方もあるんだな」くらいに思っていただければ幸いです

詳細については、いちどドキュメントを参照してみてください
(今回であればDate やArray オブジェクトが持つ様々なメソッドは特に見ておくと良いかもしれません)

require 'date'

def ask_year_and_month
  # 年月を訊いて 配列として返す
  %w[西暦 月].map do |label|
    print "#{label}を入力してください: "
    gets.to_i
  end
end

def create_monthly_days(year, month)
  # 次の月を見て、前の日に戻すことで指定した月の最後の日数がわかる
  first_day = 1
  last_day_of_month =
    Date.new(year, month, first_day).next_month.prev_day.day

  # プリント処理に回しやすいようにDate オブジェクトを配列で生成
  [*(first_day..last_day_of_month)].map do |day| # 最初の日から最後の日までの範囲を配列に展開
    Date.new(year, month, day)
  end
end

# 日付データをいい感じな表示になるように変換
def prettify_date_format(date)
  wday = %w[日 月 火 水 木 金 土][date.cwday.modulo(7)]

  # TODO: 土日の場合はフォーマットの最後に "(休)" を付与できるようにする
  "#{date.year}#{date.month}#{date.day}日は#{wday}曜日"
end

def print_days_of_month
  # splat operator で、呼び出した関数の戻り値を直接引数にして渡す
  days = create_monthly_days(*ask_year_and_month)

  days.each do |d|
    # 個々のデータは逐次フォーマットを変換して出力
    puts prettify_date_format(d)
  end
end

print_days_of_month # 処理開始

 Links

(Ruby-Doc.org は英語ではあるものの、検索窓が付いてるので、知りたい単語ですぐに調べられていいです)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

こちらで日付に関する便利メソッドが紹介されています。
[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか - Qiita
Railsの場合と紹介されていますが、active_supportrequireメソッドで読み込めば使えると思います。
ついでに、上記で紹介された便利メソッドについて、詳しく解説されているページも載せておきます。
Active Support コア拡張機能 | Rails ガイド

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

参考情報

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る