LoginSignup
4
1

More than 5 years have passed since last update.

Calendar.WEEK_OF_YEARについて

Last updated at Posted at 2016-02-10

CalendarクラスのWEEK_OF_YEAR

CalendarクラスのWEEK_OF_YEARは、一年の中で何週目かを返すfieldなのですが、week1:第一週目をいつから数えるかは、getFirstDayOfWeek() (週が何曜日からはじまるか)とgetMinimalDaysInFirstWeek()(最初の週を何日以上とするか)によって計算されます。

WEEK_OF_YEAR
public static final int WEEK_OF_YEAR
get および set のためのフィールド値で、現在の年の何週目かを示します。getFirstDayOfWeek() および getMinimalDaysInFirstWeek() で定義される年の最初の週には、値 1 が使用されます。サブクラスでは、年の最初の週より前の日に対して WEEK_OF_YEAR の値が定義されます。

今年2016年の 1/1 は金曜日なので、例えば次の月曜日1/4の週をweek1と数えるようにするためには、

setFirstDayOfWeek(Calendar.MONDAY);
setMinimalDaysInFirstWeek(4);

とします。

Android だと、、、

しかし、Android apk でコレを実装してみると、うまく動かない。。。

例えばこの記事を執筆している今日は2/10で、以下のようなコードだとweek6となってほしいのですが、week7と出力されてしまう。

    private void getWeekNumber() {
        Calendar calendar = Calendar.getInstance();

        Log.d("###", "Original week:" + calendar.get(Calendar.WEEK_OF_YEAR));
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setMinimalDaysInFirstWeek(4);

        Log.d("###", "Modified week:" + calendar.get(Calendar.WEEK_OF_YEAR));
    }

実行結果

Original week:7
Modified week:7

あれれと少しの間ハマって試行錯誤した結果、何かしらのfieldにset()すれば、期待どおりにweek6と出力されることがわかりました。

    private void getWeekNumber() {
        Calendar calendar = Calendar.getInstance();
        Log.d("###", "Time:" + calendar.getTime());
        Log.d("###", "Original week:" + calendar.get(Calendar.WEEK_OF_YEAR));

        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setMinimalDaysInFirstWeek(4);

        Log.d("###", "Time:" + calendar.getTime());
        Log.d("###", "Modified week:" + calendar.get(Calendar.WEEK_OF_YEAR));

        calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR)); // これを実行した以降は正しい結果に

        Log.d("###", "Time:" + calendar.getTime());
        Log.d("###", "Modified week:" + calendar.get(Calendar.WEEK_OF_YEAR));

    }

実行結果

Time:Wed Feb 10 22:36:22 JST 2016
Original week:7
Time:Wed Feb 10 22:36:22 JST 2016
Modified week:7
Time:Wed Feb 10 22:36:22 JST 2016
Modified week:6 // 期待通り

という不思議な結果です。getTime()の値は全部同じなのに、、、
Androidのバグ??
と思ってCalendarクラスの実装を見てみる。

まずはget(). fieldの値を返す前にcomplete() を呼んでます。

    898     public int get(int field) {
    899         complete();
    900         return fields[field];
    901     }

complete() の中では、computeTime() というやつを呼んで、最新の設定をもとにCalendar情報を計算しているのでしょうかね、名前からして。それを実行するためには、areFieldsSetfalseである必要がありますと。

    838     protected void complete() {
    839         if (!isTimeSet) {
    840             computeTime();
    841             isTimeSet = true;
    842         }
    843         if (!areFieldsSet) {
    844             computeFields();
    845             areFieldsSet = true;
    846         }
    847     }

そんでsetFirstDayOfWeek()setMinimalDaysInFirstWeek()をみてみると

   1174     public void setFirstDayOfWeek(int value) {
   1175         firstDayOfWeek = value;
   1176     }
...
   1189     public void setMinimalDaysInFirstWeek(int value) {
   1190         minimalDaysInFirstWeek = value;
   1191     }

値をセットしているだけで、特にフラグなどいじってませんので、このままget() しても再計算された値が取得できないように見えます。

一方 set() では、areFieldsSetfalse をセットしてます。
つまり、あとでcomputeする必要がありまっせということでしょうかね。

   1123     public void set(int field, int value) {
   1124         fields[field] = value;
   1125         isSet[field] = true;
   1126         areFieldsSet = isTimeSet = false; // ここ
...

set()を呼ぶと問題を回避できるのはこのためでしょうかね。

ということで、
Androidのバグ??

その他の環境では

ちなみにmacのJava SE 1.8.0_45-b14では、こういった動作にはならなかった。

import java.util.Calendar;

public class MyCal {
    public static void main(String[] args){
        Calendar calendar = Calendar.getInstance();

        System.out.println("Original:" + calendar.get(Calendar.WEEK_OF_YEAR));

        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setMinimalDaysInFirstWeek(4);

        System.out.println("Modified:" + calendar.get(Calendar.WEEK_OF_YEAR));

    }
}

実行結果

Original:7
Modified:6

多分、、、

setFirstDayOfWeek() をした後も、computeFields()しなきゃいけないのかなと。
例えばメソッドの中で

 areFieldsSet = false

するとか。

4
1
0

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
4
1