2009年12月19日

Javaで日数の計算結果がおかしい?

昨日Javaで2つの日付を指定して日数を計算させるコードを書いていたらちょっとおかしな現象に遭遇。
下記のコードで2010/1/29から2010/2/1までの日数を計算させると日数=0日になってしまう。

--------
import java.util.Calendar;
import java.util.GregorianCalendar;

public class Main {
        public static void main(String[] args) {
                useGregorianCalendar(2010, 1, 29, 2010, 2, 1);
        }
        static void useGregorianCalendar(int year_s, int month_s, int day_s,
                        int year_e, int month_e, int day_e)
        {
                Calendar start = new GregorianCalendar(year_s, month_s, day_s);
                Calendar end = new GregorianCalendar(year_e, month_e, day_e);
                System.out.println(start);
                System.out.println(end);
                long day = (end.getTimeInMillis() -
                                start.getTimeInMillis()) / 1000 / 60 / 60 / 24;
                System.out.println("日数 = " + day + "日");
        }
}
--------
実行結果
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Tokyo",offset=32400000,dstSavings=0,useDaylight=false,transitions=10,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2010,MONTH=1,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=29,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Tokyo",offset=32400000,dstSavings=0,useDaylight=false,transitions=10,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2010,MONTH=2,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=1,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
日数 = 0日
--------


そこで
++C++;// 未確認飛行 C 「経過日数の計算」
を参考にさせてもらって下記のように変更してみたところ日数=3という計算結果になった。

--------
import java.util.Calendar;
import java.util.GregorianCalendar;

public class Main {
        public static void main(String[] args) {
                System.out.println("日数 = " + (getDays(2010, 2, 1) - getDays(2010, 1, 29)) + "日");
        }
        //http://ufcpp.net/study/algorithm/o_days.html より
        static int getDays(int y, int m, int d)
        {
         // 1・2月 → 前年の13・14月
         if (m <= 2)
         {
         --y;
         m += 12;
         }
         int dy = 365 * (y - 1); // 経過年数×365日
         int c = y / 100;
         int dl = (y >> 2) - c + (c >> 2); // うるう年分
         int dm = (m * 979 - 1033) >> 5; // 1月1日から m 月1日までの日数
         return dy + dl + dm + d - 1;
        }
}
--------
実行結果
日数 = 3日
--------

計算結果がおかしいのはjava.util.GregorianCalendarでgetTimeInMillis()の結果が同じ値を返しているためらしい。
Calendar start = new GregorianCalendar(2010, 1, 29);
Calendar end = new GregorianCalendar(2010, 2, 1);
System.out.println("start.getTimeInMillis = " + start.getTimeInMillis());
System.out.println("end.getTimeInMillis = " + end.getTimeInMillis());
上記の計算結果が次のように同じ値を返している。
start.getTimeInMillis = 1267369200000
end.getTimeInMillis = 1267369200000

なんでかな?

0 件のコメント:

コメントを投稿