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

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

ただいまの
回答率

88.32%

java カレンダー作成

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 10K+
退会済みユーザー

退会済みユーザー

追記:JDKのバージョンは1.6.0_19です。
そして指示によりimportは使用できないようになっています。


コマンドライン引数で年月の値を引き渡し(201604の様に6桁で)、それでカレンダーを表示させるプログラムを考えています。

一応理想の形で表示させることが出来るようになったのですが、もっと『ここはこうするべき』『こうした方がスマートで分かりやすい』『最初から大幅にやり直すべき』などご指摘がございましたら是非お願いいたします!


public class CalShow {

    public static void main(String[] args) {

        java.util.Calendar cal = java.util.Calendar.getInstance();

        int year = Integer.parseInt(args[0].substring(0, 4));
        int month = Integer.parseInt(args[0].substring(4));

        System.out.println( year + "年" + month + "月");
        System.out.println(" 日 月 火 水 木 金 土");

        //year,month,1で年月日設定
        cal.set(year, month - 1, 1);

        //月初日が何曜日なのか設定
        int startDay = cal.get(java.util.Calendar.DAY_OF_WEEK);

        int lastDay = cal.getActualMaximum(java.util.Calendar.DATE);

        if(startDay != 7){
            for(int i = 1 ; i < startDay; i++ ){
                System.out.print("   ");
            }
        }

        int day = 1;
        for(int i = startDay; i <= 7; i++) {
            if(day < 10){
                System.out.print(" ");
            }
            System.out.print(" "+ day);
            day ++;
        }

        System.out.println("");

        for(int j = 1; j < 7; j++){
            for(int k = 0; k < 7; k++){
                if(day <= lastDay){
                    if(day < 10){
                        System.out.print(" ");
                    }
                    System.out.print(" "+ day);
                    day ++;
                }
            }
            System.out.println("");
        }
    }
}

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • KiyoshiMotoki

    2016/04/18 14:10 編集

    お使いのJDKのバージョンは何ですか?それによって、回答が変わってくる可能性がありますので。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2016/04/18 14:12

    JDKは1.6.0_19です。あと申し訳ありません、記載するのを忘れていたのですが、importは使用せずに作成したいと思っております。

    キャンセル

  • KiyoshiMotoki

    2016/04/18 14:16

    返信ありがとうございます。お手数ですが、「JDKは1.6.0_19です。」は質問欄に追記願います。誰もがこの"情報の追加・修正の依頼をする"欄を読むとは限りませんので。あと、「importは使用せずに作成したいと思っております。」は、なぜですか?理由によっては、その方針自体、考え直すべきかもしれません。

    キャンセル

回答 3

checkベストアンサー

+1

 入力値をチェックしていない

入力値が渡されなかった場合、ArrayIndexOutOfBoundsExceptionが発生してプログラムが異常終了します。

また、"201613"や"123456789"など、年月として無効な値が渡された場合でも、そのまま実行されてしまいます。
これに関しては、cal.setを実行する前にcal.setLenient(false)を実行しておくことで、おかしな日付を黙って計算してしまう事態を防ぐことができます。
https://docs.oracle.com/javase/jp/6/api/java/util/Calendar.html#setLenient(boolean)

 文字数の調整方法

if (day < 10) {
    System.out.print(" ");
}
System.out.print(" " + day);

部分で一桁の日付の表示幅を調整しながら出力していますが、String.formatメソッドを使用すれば、以下のように簡潔に書けます。

System.out.print(String.format("% 3d", day));

 定数の値に依存した実装

for (int i = startDay; i <= 7; i++) {

などの部分は、Calendar.SUNDAY = 1であることなどに依存した実装になっています。
しかし、万が一、後のバージョンアップで曜日も(月のように)0から始まる連番に変更された場合、このプログラムは正しく動かなくなります。
定数の値が何なのかを気にしなくても良いように実装すべきです。

例えば、あまり良いコードではありませんが、以下のような感じです。

// year,month,1で年月日設定
cal.set(year, month - 1, 1);

// 理由は不明だが、ここでこれを呼び出しておかないと1月を指定したときにおかしな動きをする。
// おそらく年・月・日以外のフィールドの値が変更されていないためと思われ。
cal.getTime();

// さらに、その週の日曜日に日付を設定
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);

while (("" + cal.get(Calendar.YEAR) + (cal.get(Calendar.MONTH) + 1)).compareTo("" + year + month) <= 0) {
    if (cal.get(Calendar.MONTH) + 1 != month) {
        // 前月の間は空欄表示
        System.out.print("   ");
    } else {
        System.out.print(String.format("% 3d", cal.get(Calendar.DAY_OF_MONTH)));
    }

    // 土曜日なら折り返し
    if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
        System.out.println();
    }
    cal.add(Calendar.DAY_OF_MONTH, 1);
}

 そして指示によりimportは使用できないようになっています。

これを指示した方に、その理由を質問することを強くおすすめします。

何のための制限なのか、正直 理解できません。

あるいは、
「java.langパッケージ以外は使わないこと」
という意味なのかもしれません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/18 17:12

    定数に依存しない実装を教えていただきありがとうございます。
    表示幅の簡潔な表し方についても大変勉強になりました!

    ちなみにimportを使うな、という指示は私がフルネームでAPIメソッドを使用出来るかどうかをチェックしていただけだそうでした;

    キャンセル

  • 2016/04/18 18:37

    お役に立てたなら、幸いです。

    > 私がフルネームでAPIメソッドを使用出来るかどうかをチェックしていただけだそうでした;

    それができたところで何がうれしいのか分かりかねますが(笑)、了解しました。
    丁寧なご報告、ありがとうございます。

    キャンセル

+1

その月の最終日はgetActualMaximumというメソッドにCalendar.DATEを渡せば取得できます。
また、もっとCalendarクラスを活用すれば表示の部分も簡略化できそうです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/18 15:34

    最終日取得についてのご指摘ありがとうございます。
    簡略化は是非とも行いたいところですので、『もっとCalendarクラスを活用』についてももう少し詳しくご教授願えませんでしょうか?

    キャンセル

+1

for(int j = 1; j < 7; j++){
    for(int k = 0; k < 7; k++){
        if(day <= lastDay){
            if(day < 10){
                System.out.print(" ");
            }
            System.out.print(" "+ day);
            day ++;
        }
    }
    System.out.println("");
}


とりあえず、ここのfor文のネストは可読性を落とすだけなのでやめたほうがいいでしょう。
そのうえでjava.util.Calendarを有効活用するならこんなコードもありですね。

java.util.Calendar cal = java.util.Calendar.getInstance();
cal.set(year, month - 1, 1);

int monthStartDayOfWeek = cal.get(java.util.Calendar.DAY_OF_WEEK);

int dateConst = java.util.Calendar.DATE;

System.out.println( year + "/" + (month--) + "");
System.out.print(" sun mon tue wed thu fri sat");

for(int i = 1; ; i++) {
    if(i % 7 == 1){ System.out.println(); }
    if (i < monthStartDayOfWeek) {
        System.out.print("    ");
        continue;
    }
    System.out.print(String.format("% 4d", cal.get(dateConst)));
    cal.add(dateConst, 1);
    if (cal.get(java.util.Calendar.MONTH) != month) {
        System.out.println();
        break;
    }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/18 17:14

    可読性についてのご指摘ありがとうございました。
    なるべくfor文がネストしないよう作っていきたいと思います。
    まだまだ分からないことばかりで、有効活用の記載分についてはまだ理解出来かねる部分が多いのですが、理解できるよう頑張っていきます。
    またよろしくお願いいたします。

    キャンセル

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

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

関連した質問

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