LoginSignup
1
1

More than 5 years have passed since last update.

[Java]年月日から曜日を算出(Calendarクラスは使わない)

Posted at

はじめに

先日、古本屋で見つけた「暗算の達人」という本を読んでいます。
そこに、年月日から曜日を算出する方法が乗っていたので、自分の誕生日を使って試してみたら、見事に一致。

数学たのしー!

で、

プログラムに落とし込んでみた。
普段Calendarクラスとか使ってやってるから、自分で曜日算出するとか新鮮。

プログラミングたのしー!

処理

package math;

import java.util.HashMap;
import java.util.Map;

/**
 * 年月日から曜日の算出
 * - 1900年代と2000年代は計算できる
 * - 閏年は考慮してない
 */
public class CalcDayOfWeek {

    /** 月に対する符号(key:月/val:符号) */
    private static final Map<Integer, Integer> SIGN_OF_MONTH = new HashMap<>();
    static {
        SIGN_OF_MONTH.put( 1, 6);
        SIGN_OF_MONTH.put( 2, 2);
        SIGN_OF_MONTH.put( 3, 2);
        SIGN_OF_MONTH.put( 4, 5);
        SIGN_OF_MONTH.put( 5, 0);
        SIGN_OF_MONTH.put( 6, 3);
        SIGN_OF_MONTH.put( 7, 5);
        SIGN_OF_MONTH.put( 8, 1);
        SIGN_OF_MONTH.put( 9, 4);
        SIGN_OF_MONTH.put(10, 6);
        SIGN_OF_MONTH.put(11, 2);
        SIGN_OF_MONTH.put(12, 4);
    }

    /** 曜日に対する符号(key:符号/val:算出結果) */
    private static final Map<Integer, String> SIGN_OF_WEEK  = new HashMap<>();
    static {
        SIGN_OF_WEEK.put(1, "Mon.");
        SIGN_OF_WEEK.put(2, "Tue.");
        SIGN_OF_WEEK.put(3, "Wed.");
        SIGN_OF_WEEK.put(4, "Thu.");
        SIGN_OF_WEEK.put(5, "Fri.");
        SIGN_OF_WEEK.put(6, "Sat.");
        SIGN_OF_WEEK.put(0, "Sun.");
    }

    /** 年(先頭2桁)に対する比重 */
    private static final Map<Integer, Integer> WEIGHT_OF_YEAR = new HashMap<>();
    static {
        WEIGHT_OF_YEAR.put(19, 1);
        WEIGHT_OF_YEAR.put(20, 0);
    }

    /**
     * メイン({@link #calcDayOfWeek}を呼び出すだけ)
     * @param args
     */
    public static void main(String[] args) {
        calcDayOfWeek("1993/09/17"); // とりあえず、僕の誕生日
        calcDayOfWeek("2017/09/17"); // 今年の誕生日

        calcDayOfWeek("2001/09/11"); // アメリカ同時多発テロ
        calcDayOfWeek("2011/03/11"); // 東日本大震災
        calcDayOfWeek("1989/11/09"); // ベルリンの壁崩壊
    }

    /**
     * 曜日算出
     * - 年:下2桁を25%した値と、下2桁を足す。(但し、何年代かにより比重を加算する)
     * - 月:月に対する符号のマッピングから取得
     * - 日:そのまま使用
     * @param yyyyMMdd
     */
    public static void calcDayOfWeek(String yyyyMMdd) {
        if (yyyyMMdd == null)
            return;
        yyyyMMdd = yyyyMMdd.replaceAll("-", "").replaceAll("/", "").replaceAll(" ", "");
        if (!checkFormat(yyyyMMdd))
            return;

        int yy     = Integer.parseInt(yyyyMMdd.substring(2, 4));
        int mm     = Integer.parseInt(yyyyMMdd.substring(4, 6));
        int dd     = Integer.parseInt(yyyyMMdd.substring(6, 8));
        int weight = WEIGHT_OF_YEAR.get(Integer.parseInt(yyyyMMdd.substring(0, 2)));

        int signOfYear  = (yy / 4) + yy + weight;
        int signOfMonth = SIGN_OF_MONTH.get(mm); 
        int signOfDay   = dd;

        System.out.println(String.format("%s is %s",yyyyMMdd, SIGN_OF_WEEK.get((signOfYear + signOfMonth + signOfDay) % 7)));
    }

    private static boolean checkFormat(String yyyyMMdd) {
        try {
            Integer.parseInt(yyyyMMdd);
            return yyyyMMdd.length() == 8;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}

出力結果

とりあえず自分の誕生日と、世界的なニュースあたりを...

19930917 is Fri.
20170917 is Sun.
20010911 is Tue.
20110311 is Fri.
19891109 is Thu.

感想

・計算自体は面倒臭くないけど、月に対する符号のマッピング(SIGN_OF_MONTH)を覚えるのがしんどい
・閏年を考慮するともうちょっと処理が複雑になるけど、そこまで大した事なさそう(※調べ次第、更新するかも)
・1800年代とか2100年代とかは、知らん(※調べ次第、更新するかも)

頭の中で計算できるようになると、合コンとかで使えてモテそうですね。(適当)

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1