Calendar.HOUR_OF_DAY confusion

2019-07-24 17:48发布

问题:

I have this piece of code:

Calendar cal = Calendar.getInstance();
cal.setTime(pDatum);
cal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(pHHMMTP.substring(0, 2)));
cal.set(Calendar.MINUTE, Integer.valueOf(pHHMMTP.substring(2, 4)));
cal.set(Calendar.MILLISECOND, 0);
System.out.println(cal.getTime());

where pDatum is Sun Mar 27 00:00:00 CET 2016, pHHMMTP is 02485 and pHHMMTP.substring(0, 2) is 02.

The output is:

Sun Mar 27 03:48:00 CEST 2016

I would expect:

Sun Mar 27 02:48:00 CEST 2016

First I thought it is a TimeZone issue but with this code I get the same output:

Calendar cal = Calendar.getInstance();
TimeZone tz = TimeZone.getTimeZone("GMT");
cal.setTimeZone(tz);
cal.setTime(pDatum);
cal.set(Calendar.HOUR_OF_DAY, Integer.valueOf(pHHMMTP.substring(0, 2)));
cal.set(Calendar.MINUTE, Integer.valueOf(pHHMMTP.substring(2, 4)));
cal.set(Calendar.MILLISECOND, 0);

Do you see my problem?

回答1:

CET means Central European Timezone. In Europe, there is a notion of Daylight Saving Time.

Basically, in winter, the hour is shifted from 1h. For practical reasons (quality of sleep actually), the time switch is done on the first sunday of spring which is the 27th of march in 2016. Also, for practical reasons, the time switch is done during the night, between 02:00 AM and 03:00 AM, so the clocks counts down like this: 01:58, 01:59, 03:00, 03:01. This means, Sun Mar 27 02:48:00 CET 2016 does not exist.
As a consequence, if you run your code on Sun Mar 27, you will get 03:48 but if you run it on Mon Mar 28, you will get 02:48.

Try with both dates :

//Date date = new SimpleDateFormat("dd/MM/yyyy z").parse("27/03/2016 CET");
Date date = new SimpleDateFormat("dd/MM/yyyy z").parse("28/03/2016 CET");

Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 2);
cal.set(Calendar.MINUTE, 48);
cal.set(Calendar.MILLISECOND, 0);

System.out.println(cal.getTime());

Output :

Mon Mar 28 02:48:00 CEST 2016



回答2:

It's a TimeZone problem, you're building the calendar in GMT, but printing the date in CEST zone.

Edit:

When the date is printed out with the same timezone, then it's ok:

  Calendar cal = Calendar.getInstance();
  TimeZone tz = TimeZone.getTimeZone("GMT");
  cal.setTimeZone(tz);
  cal.set(Calendar.HOUR_OF_DAY, 2);
  cal.set(Calendar.MINUTE, 48);
  cal.set(Calendar.MILLISECOND, 0);

  System.out.println(cal.getTime()); // <-- System default Zone

  DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
  formatter.setTimeZone(tz);

  System.out.print(formatter.format(cal.getTime())); // <-- Same TimeZone

Output:

Tue Mar 22 03:48:06 CET 2016
Tue Mar 22 02:48:06 GMT 2016