简体   繁体   中英

Wrong output from Java Calendar API

Calendar.setTimeInMillis and Calendar.getTime works weird. It returns incorrect date results.

Java Code

public static void main(String[] args)
{
    Calendar cal = Calendar.getInstance();
    final int oneDay = 24 * 60 * 60 * 1000;

    for(int i=0; i < 30; i++) {
        cal.setTimeInMillis(System.currentTimeMillis() - i * oneDay);
        System.out.println(cal.getTime());
    }

}

Output

Tue Jun 24 17:50:35 IST 2014
Mon Jun 23 17:50:35 IST 2014
Sun Jun 22 17:50:35 IST 2014
Sat Jun 21 17:50:35 IST 2014
Fri Jun 20 17:50:35 IST 2014
Thu Jun 19 17:50:35 IST 2014
Wed Jun 18 17:50:35 IST 2014
Tue Jun 17 17:50:35 IST 2014
Mon Jun 16 17:50:35 IST 2014
Sun Jun 15 17:50:35 IST 2014
Sat Jun 14 17:50:35 IST 2014
Fri Jun 13 17:50:35 IST 2014
Thu Jun 12 17:50:35 IST 2014
Wed Jun 11 17:50:35 IST 2014
Tue Jun 10 17:50:35 IST 2014
Mon Jun 09 17:50:35 IST 2014
Sun Jun 08 17:50:35 IST 2014
Sat Jun 07 17:50:35 IST 2014
Fri Jun 06 17:50:35 IST 2014
Thu Jun 05 17:50:35 IST 2014
Wed Jun 04 17:50:35 IST 2014
Tue Jun 03 17:50:35 IST 2014
Mon Jun 02 17:50:35 IST 2014
Sun Jun 01 17:50:35 IST 2014
Sat May 31 17:50:35 IST 2014
Sat Jul 19 10:53:23 IST 2014
Fri Jul 18 10:53:23 IST 2014
Thu Jul 17 10:53:23 IST 2014
Wed Jul 16 10:53:23 IST 2014
Tue Jul 15 10:53:23 IST 2014

After "May 31" , It would be "May 30 , May 29 , May 28 & May 27" but it returns incorrect date.

    Sat May 31 17:50:35 IST 2014
    Sat Jul 19 10:53:23 IST 2014
    Fri Jul 18 10:53:23 IST 2014
    Thu Jul 17 10:53:23 IST 2014
    Wed Jul 16 10:53:23 IST 2014
    Tue Jul 15 10:53:23 IST 2014

Is this bug in Calendar.getTime() ?

No, it is not a bug in Calendar.getTime() .

You are using int , and when the numbers become too big to fit in an int , then i * oneDay overflows and you get strange results.

Solution: Use long instead:

final long oneDay = 24L * 60 * 60 * 1000;

(Your code also doesn't take daylight savings into account, at some point you'll see a shift of an hour if your timezone has daylight savings).

You are performing integer arithmetic and have overflowed an int. The max value of a (signed) int is 2,147,483,647 (2^31-1). There are 86,400,000 milliseconds in ONE_DAY. On day 25 you reach 2,160,000,000, which is a larger value than can be represented in an int and you overflow into negative numbers.

You can solve this by doing your math with longs instead of ints.

public static void main(String[] args)
{
    Calendar cal = Calendar.getInstance();
    final long oneDay = 24 * 60 * 60 * 1000;

    for(int i=0; i < 30; i++) {
        cal.setTimeInMillis(System.currentTimeMillis() - i * oneDay);
        System.out.println(cal.getTime());
    }

}

Replace

final int oneDay = 24 * 60 * 60 * 1000;

with

final long oneDay = 24 * 60 * 60 * 1000;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM