Thinkers'Studio
JavaとC言語の自習ツール
指定日のn日後を調べるプログラム例(Java版)

 今回は、指定日の n日後の日付を調べるプログラムです。
 Calendar クラスに同様の機能がありますが(下記で今週のクイズへ、答えは次回のJavaTipsで)、ここでは自作のクラスでいくつかのメソッドを用意して実現する例を示します。 シンプルですが、クラスの一連の操作を考える参考にもなります。

  (例) 2020年東京オリンピック開会式(2020/07/24) の 1000日前は?
     2014年の立春(2014/02/04)の 87日後は? 八十八夜は、新茶の摘み時です

クラスの内容 】
 年月日をクラスのメンバ変数とし、コンストラクタ(SetDate)で指定の日付を設定します。
 自作メソッド(addDate)に n を渡すと、n日後の日付を求めてメンバ変数を更新します。 n に負の値を指定すると、過去の日付を調べることもできます。 結果の日付文字列を(getDate)メソッドで取り出して表示します。
 ※ n日後を求める処理手順は、プログラムの下に示します。コードから読み取ってみてください。

【 指定日の n日後の日付を調べるプログラム例 】  指定される日付は正しいものとします。
class SetDate {
    private int y;
    private int m;
    private int d;
    // --- コンストラクタ
    SetDate( int y, int m, int d ) {
        this.y = y; this.m = m; this.d = d;
    }
    // --- メンバ変数の日付文字列を返す
    String getDate() {
        return y + "年" + m + "月" + d + "日";
    }
    // --- yがうるう年か調べる
    private boolean isLeapYear() {
        if( y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ) return true;
        else return false;
    }
    // --- メンバ変数をn日後の日付で更新する
    void addDate( int n ) {
        int days[][] =
        { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
        , { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
        int nday[] = new int[12];

        if( n == 0 ) return;
        nday = isLeapYear() ? days[1] : days[0];
        d += n;
        if( n > 0 ) { //将来日付 dが当月内になるまで日数を引いてはmを進める
            while( d > nday[m-1] ) {
                d -= nday[m-1];
                if( ++m > 12 ) {
                    ++y; m = 1;
                    nday = isLeapYear() ? days[1] : days[0];
                }
            }
        } else { //過去日付 dが正の日付になるまで日数を足してはmを戻す
            while( d <= 0 ) {
                d += nday[m-1];
                if( --m < 1 ) {
                    --y; m = 12;
                    nday = isLeapYear() ? days[1] : days[0];
                }
            }
        }
    }
}
// -------------------------------------------------------------------
class NdayTest {
    public static void main( String[] args ) {

        SetDate nd = new SetDate( 2020, 7, 24 );
        System.out.println( "東京五輪開会式は " + nd.getDate() );
        nd.addDate( -1000 );
        System.out.println( "その1000日前は " + nd.getDate() );
    }
}
実行結果
東京五輪開会式は 2020年7月24日
その1000日前は 2017年10月28日

【 処理手順 】
 ymd の d に n を加算してしまい、d が当月になるまで、m を進めてその分の日数を引きます。
   たとえば 2013/10/10 の 90日後なら、まず d に 90 を足す --> (2013/10/100)
   ・ ひと月進める --> d から10月の 31日を引き m は 11月へ(2013/11/69)
   ・ 11から12月へも同様 --> (2013/12/39)
   ・ さらに翌年の 1月へ --> (2014/01/09)  ・・・ d が当月の日数内になったので、処理は終わり
 y がうるう年かどうかで 2月の日数が異なるため、その判定も必要です。
 過去日付を求める n < 0 の場合は、上記と逆です。m を戻し日数は足し算していく処理になります。たとえば n が -90 なら 2013/10/-80 から始め、d が 1以上の有効な日付になるまで繰り返します。

(今週のクイズです)
 上のプログラムを、Calendarクラスを使って実現するとしたら、どんなメソッドを使えばよいでしょうか?
  (答えは、次回の Java の Tips で ・・・ )

前回のクイズの答え: (前回の問題を見る
final static int LIMIT = 1000000; の定義を追加し下記の main で求めます。効率化の着目点は isPrimeNum と同じ。2以外の偶数は素数でないことが分かっているので候補から外し、それ以外を isPrimeNum に調べさせます。
public static void main( String[] args ) {
    System.out.print( LIMIT + "を超えない最大の素数は・・・ " );
    int n = ( LIMIT>2&&LIMIT%2 == 0 ? LIMIT-1 : LIMIT ); 
    while( n >= 2 ) {
        if( isPrimeNum( n ) ) {
            System.out.println( n ); break;
        }
        n -= 2;
    }
}