曜日計算

AlarmClockのソースを参考に今日がXdayだった場合、次にチェックの入ったYdayを求める。という計算ロジックを作成する

AlarmClockのソース

曜日チェックの画面
AlarmClockのAlarms.javaに曜日計算している箇所

        /**
         * returns number of days from today until next alarm
         * @param c must be set to today
         */
        public int getNextAlarm(Calendar c) {
            if (mDays == 0) return -1;
            int today = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7;

            int day, dayCount;
            for (dayCount = 0; dayCount < 7; dayCount++) {
                day = (today + dayCount) % 7;
                if ((mDays & (1 << day)) > 0) {
                    break;
                }
            }
            return dayCount;
        }

このソースを見ると、日曜〜土曜までを2^nで定義していると思われる。
mDaysはチェックした日付の論理和が入っている。
で、今日をXdayとして、CalendarクラスからDayOfWeekを求めている。
1bitずつシフトしてYdayの値と論理演算をしてbitが立っている場合はループを抜けている。

このロジックはXdayからYdayまでN日後という場合のNを求めいている

だが、ちょっとまってほしい。
これなんだ?

int today = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7;

これの「+5」の意味が分からない・・
きっとGoogleのことだから、意味のないことはしないはず。

■考察

Calenderクラスでは日曜日を"1"で〜土曜日"6"で定義されている。
これに合わせて、曜日値を2^nにしたら、こうなると思う
日曜日:0x01
月曜日:0x02
火曜日:0x04
水曜日:0x08
木曜日:0x10
金曜日:0x20
土曜日:0x30

ところが、AlarmClockでは以下のように定義されている

 * 0x00:  no day
 * 0x01:  Monday
 * 0x02:  Tuesday
 * 0x04:  Wednesday
 * 0x08:  Thursday
 * 0x10:  Friday
 * 0x20:  Saturday
 * 0x40:  Sunday

Calenderは日曜日が週初めなのに、AlarmClockでは週初めを月曜にしている・・・

なのでループ値を表にするとこうなる

日曜日 月曜日 火曜日 水曜日 木曜日 金曜日 土曜日
google 64 1 2 4 8 16 32
Calendar 1 2 3 4 5 6 7
(today + 5) % 7 6 0 1 2 3 4 5
ループカウンタ bitシフト(値)
0 6(64) 0(1) 1(2) 2(4) 3(8) 4(16) 5(32)
1 0(1) 1(2) 2(4) 3(8) 4(16) 5(32) 6(64)
2 1(2) 2(4) 3(8) 4(16) 5(32) 6(64) 0(1)
3 2(4) 3(8) 4(16) 5(32) 6(64) 0(1) 2(2)
4 3(8) 4(16) 5(32) 6(64) 0(1) 2(2) 2(4)
5 4(16) 5(32) 6(64) 0(1) 2(2) 2(4) 3(8)
6 5(32) 6(64) 0(1) 2(2) 2(4) 3(8) 4(16)
  1. 5をしている理由はわかったが、なんで月曜から始めてんのかがわからない。

個人的にはこうしたい

日曜日:0x01
月曜日:0x02
火曜日:0x04
水曜日:0x08
木曜日:0x10
金曜日:0x20
土曜日:0x30

ソース

	public static int getNextAlarm(Calendar c, int mDays) {
		if (mDays == 0)	return -1;
		int today = c.get(Calendar.DAY_OF_WEEK) - 1;

		int day, dayCount;
		for (dayCount = 0; dayCount < 7; dayCount++) {
			day = (today + dayCount) % 7;
			if ((mDays & (1 << day)) > 0) {
				break;
			}
		}
		return dayCount;
	}
}

結果

日曜日 月曜日 火曜日 水曜日 木曜日 金曜日 土曜日
1 2 4 8 16 32 64
Calendar 1 2 3 4 5 6 7
today% 7 0 1 2 3 4 5 6
ループカウンタ bitシフト(値)
0 0(1) 1(2) 2(4) 3(8) 4(16) 5(32) 6(64)
1 1(2) 2(4) 3(8) 4(16) 5(32) 6(64) 0(1)
2 2(4) 3(8) 4(16) 5(32) 6(64) 0(1) 1(2)
3 3(8) 4(16) 5(32) 6(64) 0(1) 1(2) 2(4)
4 4(16) 5(32) 6(64) 0(1) 1(2) 2(4) 3(8)
5 5(32) 6(64) 0(1) 1(2) 2(4) 3(8) 4(16)
6 6(64) 0(1) 1(2) 2(4) 3(8) 4(16) 5(32)

■ソース

import java.util.Calendar;

public class Main {
	static final String[] DAY_OF_WEEK = { "dummy", "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日" };

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		int val = 32;
		int shift = 5;
		int result = 1 << shift;
		System.out.println("v:" + val + "res:" + result);

		// bit表示(土金木水火月日)
		// days = binary(0101000) 水金をON
		int days = Integer.parseInt("0101000", 2);
		System.out.println("days:" + days + " binary:" + Integer.toBinaryString(days));

		// 2011/3/24(木)
		Calendar c = Calendar.getInstance();
		c.set(2011, 2, 24);
		showCalender(c);
		int add = getNextAlarm(c, days);
		c.add(Calendar.DAY_OF_YEAR, add);
		showCalender(c);
	}

	public static int getNextAlarm(Calendar c, int mDays) {
		if (mDays == 0)
			return -1;
		int today = c.get(Calendar.DAY_OF_WEEK) - 1;
		int day, dayCount; // day:bit shiftの数

		System.out.println("today:" + today);
		for (dayCount = 0; dayCount < 7; dayCount++) {
			day = (today + dayCount) % 7;
			int value = mDays & (1 << day);
			System.out.print("[" + DAY_OF_WEEK[day + 1] + "] bit_shift:" + dayCount + " " + " value:" + value);
			if ((mDays & (1 << day)) > 0) {
				System.out.println("    !!!HIT");
				break;
			}
			System.out.println();
		}
		return dayCount;
	}

	public static void showCalender(Calendar cal) {
		StringBuilder sb = new StringBuilder();
		sb.append((cal.get(Calendar.MONTH) + 1) + "月 ");
		sb.append(cal.get(Calendar.DATE) + "日 ");
		sb.append(cal.get(Calendar.HOUR) + "時 ");
		sb.append(cal.get(Calendar.MINUTE) + "分 ");
		sb.append(DAY_OF_WEEK[cal.get(Calendar.DAY_OF_WEEK)]);
		System.out.println(sb.toString());
	}
}