barrel
asked on
Gregorian Calendar one hour off
Hi, I have a small question:
The following works:
// 2005-10-30
Date theDate = new Date (1130623200000L);
// 07:21:35
Time theTime = new Time (22895000L);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(theDate);
calendar.set(Calendar.HOUR , theTime.getHours());
calendar.set(Calendar.MINU TE, theTime.getMinutes());
calendar.set(Calendar.SECO ND, theTime.getSeconds());
assertTrue (calendar.get (Calendar.HOUR) == 7);
The following does not work (resulting hour is 6 instead of 7)
// 2005-10-30
Date theDate = new Date (1130623200000L);
// 07:21:35
Time theTime = new Time (22895000L);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(theDate);
calendar.add(Calendar.HOUR , theTime.getHours());
calendar.add(Calendar.MINU TE, theTime.getMinutes());
calendar.add(Calendar.SECO ND, theTime.getSeconds());
assertTrue (calendar.get (Calendar.HOUR) == 7);
My guess is that this has something to do with daylight savings/ summer vs winter time... Can anyone explain?
Barry
The following works:
// 2005-10-30
Date theDate = new Date (1130623200000L);
// 07:21:35
Time theTime = new Time (22895000L);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(theDate);
calendar.set(Calendar.HOUR
calendar.set(Calendar.MINU
calendar.set(Calendar.SECO
assertTrue (calendar.get (Calendar.HOUR) == 7);
The following does not work (resulting hour is 6 instead of 7)
// 2005-10-30
Date theDate = new Date (1130623200000L);
// 07:21:35
Time theTime = new Time (22895000L);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(theDate);
calendar.add(Calendar.HOUR
calendar.add(Calendar.MINU
calendar.add(Calendar.SECO
assertTrue (calendar.get (Calendar.HOUR) == 7);
My guess is that this has something to do with daylight savings/ summer vs winter time... Can anyone explain?
Barry
You are adding time instead of setting it - you are adding the hour of the day to the hour of the day, and the same for the minutes and seconds.
ASKER
Sure thing, but for the date 2005-10-30, the initial hour is zero. Adding 7 to zero should lead to seven, not six.... Or am I misinterpreting something? Additionally, this way of date handling works for 99% of the dates we process. There are just a few cases (one of them mentioned in the testcase) in which it doesn't work....
//The following does not work (resulting hour is 6 instead of 7)
// 2005-10-30
Date theDate = new Date (1130623200000L);
// 07:21:35
Time theTime = new Time (22895000L);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(theDate);
////////////////////////// ////////// ////////// ////////// ERRORRRR// ////////// ////////// /////////
calendar.add(Calendar.HOUR , theTime.getHours()); //use calendar.set
calendar.add(Calendar.MINU TE, theTime.getMinutes());//us e calender.set
calendar.add(Calendar.SECO ND, theTime.getSeconds());//us e calender.set
assertTrue (calendar.get (Calendar.HOUR) == 7);
Do u really have to use calender.add function???
// 2005-10-30
Date theDate = new Date (1130623200000L);
// 07:21:35
Time theTime = new Time (22895000L);
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(theDate);
//////////////////////////
calendar.add(Calendar.HOUR
calendar.add(Calendar.MINU
calendar.add(Calendar.SECO
assertTrue (calendar.get (Calendar.HOUR) == 7);
Do u really have to use calender.add function???
ASKER
No, I do not ;-)
I have become the maintainer of a project for which I did not write the code. The above illustrates one of the bugs I found and corrected. So... the problem is solved, but the big question WHY??? remains.
So I am not looking for a solution, I am looking for an explanation.
I have become the maintainer of a project for which I did not write the code. The above illustrates one of the bugs I found and corrected. So... the problem is solved, but the big question WHY??? remains.
So I am not looking for a solution, I am looking for an explanation.
here is why...................
calendar fields can be changed using three methods: set(), add(), and roll().
set(f, value) changes field f to value. In addition, it sets an internal member variable to indicate that field f has been changed. Although field f is changed immediately, the calendar's milliseconds is not recomputed until the next call to get(), getTime(), or getTimeInMillis() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a field using set(), other fields may also change, depending on the field, the field value, and the calendar system. In addition, get(f) will not necessarily return value after the fields have been recomputed. The specifics are determined by the concrete calendar class.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling set(Calendar.MONTH, Calendar.SEPTEMBER) sets the calendar to September 31, 1999. This is a temporary internal representation that resolves to October 1, 1999 if getTime()is then called. However, a call to set(Calendar.DAY_OF_MONTH, 30) before the call to getTime() sets the calendar to September 30, 1999, since no recomputation occurs after set() itself.
add(f, delta) adds delta to field f. This is equivalent to calling set(f, get(f) + delta) with two adjustments:
Add rule 1. The value of field f after the call minus the value of field f before the call is delta, modulo any overflow that has occurred in field f. Overflow occurs when a field value exceeds its range and, as a result, the next larger field is incremented or decremented and the field value is adjusted back into its range.
Add rule 2. If a smaller field is expected to be invariant, but it is impossible for it to be equal to its prior value because of changes in its minimum or maximum after field f is changed, then its value is adjusted to be as close as possible to its expected value. A smaller field represents a smaller unit of time. HOUR is a smaller field than DAY_OF_MONTH. No adjustment is made to smaller fields that are not expected to be invariant. The calendar system determines what fields are expected to be invariant.
In addition, unlike set(), add() forces an immediate recomputation of the calendar's milliseconds and all fields.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling add(Calendar.MONTH, 13) sets the calendar to September 30, 2000. Add rule 1 sets the MONTH field to September, since adding 13 months to August gives September of the next year. Since DAY_OF_MONTH cannot be 31 in September in a GregorianCalendar, add rule 2 sets the DAY_OF_MONTH to 30, the closest possible value. Although it is a smaller field, DAY_OF_WEEK is not adjusted by rule 2, since it is expected to change when the month changes in a GregorianCalenda
calendar fields can be changed using three methods: set(), add(), and roll().
set(f, value) changes field f to value. In addition, it sets an internal member variable to indicate that field f has been changed. Although field f is changed immediately, the calendar's milliseconds is not recomputed until the next call to get(), getTime(), or getTimeInMillis() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a field using set(), other fields may also change, depending on the field, the field value, and the calendar system. In addition, get(f) will not necessarily return value after the fields have been recomputed. The specifics are determined by the concrete calendar class.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling set(Calendar.MONTH, Calendar.SEPTEMBER) sets the calendar to September 31, 1999. This is a temporary internal representation that resolves to October 1, 1999 if getTime()is then called. However, a call to set(Calendar.DAY_OF_MONTH,
add(f, delta) adds delta to field f. This is equivalent to calling set(f, get(f) + delta) with two adjustments:
Add rule 1. The value of field f after the call minus the value of field f before the call is delta, modulo any overflow that has occurred in field f. Overflow occurs when a field value exceeds its range and, as a result, the next larger field is incremented or decremented and the field value is adjusted back into its range.
Add rule 2. If a smaller field is expected to be invariant, but it is impossible for it to be equal to its prior value because of changes in its minimum or maximum after field f is changed, then its value is adjusted to be as close as possible to its expected value. A smaller field represents a smaller unit of time. HOUR is a smaller field than DAY_OF_MONTH. No adjustment is made to smaller fields that are not expected to be invariant. The calendar system determines what fields are expected to be invariant.
In addition, unlike set(), add() forces an immediate recomputation of the calendar's milliseconds and all fields.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling add(Calendar.MONTH, 13) sets the calendar to September 30, 2000. Add rule 1 sets the MONTH field to September, since adding 13 months to August gives September of the next year. Since DAY_OF_MONTH cannot be 31 in September in a GregorianCalendar, add rule 2 sets the DAY_OF_MONTH to 30, the closest possible value. Although it is a smaller field, DAY_OF_WEEK is not adjusted by rule 2, since it is expected to change when the month changes in a GregorianCalenda
BTW:roll function--------------
roll(f, delta) adds delta to field f without changing larger fields. This is equivalent to calling add(f, delta) with the following adjustment:
Roll rule. Larger fields are unchanged after the call. A larger field represents a larger unit of time. DAY_OF_MONTH is a larger field than HOUR.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling roll(Calendar.MONTH, 8) sets the calendar to April 30, 1999. Add rule 1 sets the MONTH field to April. Using a GregorianCalendar, the DAY_OF_MONTH cannot be 31 in the month April. Add rule 2 sets it to the closest possible value, 30. Finally, the roll rule maintains the YEAR field value of 1999.
Example: Consider a GregorianCalendar originally set to Sunday June 6, 1999. Calling roll(Calendar.WEEK_OF_MONT H, -1) sets the calendar to Tuesday June 1, 1999, whereas calling add(Calendar.WEEK_OF_MONTH , -1) sets the calendar to Sunday May 30, 1999. This is because the roll rule imposes an additional constraint: The MONTH must not change when the WEEK_OF_MONTH is rolled. Taken together with add rule 1, the resultant date must be between Tuesday June 1 and Saturday June 5. According to add rule 2, the DAY_OF_WEEK, an invariant when changing the WEEK_OF_MONTH, is set to Tuesday, the closest possible value to Sunday (where Sunday is the first day of the week).
roll(f, delta) adds delta to field f without changing larger fields. This is equivalent to calling add(f, delta) with the following adjustment:
Roll rule. Larger fields are unchanged after the call. A larger field represents a larger unit of time. DAY_OF_MONTH is a larger field than HOUR.
Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling roll(Calendar.MONTH, 8) sets the calendar to April 30, 1999. Add rule 1 sets the MONTH field to April. Using a GregorianCalendar, the DAY_OF_MONTH cannot be 31 in the month April. Add rule 2 sets it to the closest possible value, 30. Finally, the roll rule maintains the YEAR field value of 1999.
Example: Consider a GregorianCalendar originally set to Sunday June 6, 1999. Calling roll(Calendar.WEEK_OF_MONT
ASKER
Yep, I have been reading the javadoc as well but this still leaves me puzzled.
Date 1: 2005-10-30 (and I checked, hh:ii:ss are set to 00:00:00)
set (Calendar.HOUR, 7) (which results in the expected value) should be the same as add (Calendar.HOUR, 7) on date with hours set to 0, which is the equivalent of set (calendar.HOUR, get (which is 0) + 7)
Date 1: 2005-10-30 (and I checked, hh:ii:ss are set to 00:00:00)
set (Calendar.HOUR, 7) (which results in the expected value) should be the same as add (Calendar.HOUR, 7) on date with hours set to 0, which is the equivalent of set (calendar.HOUR, get (which is 0) + 7)
>>My guess is that this has something to do with daylight savings/ summer vs winter time... Can anyone explain?
Very probably. In the case of my machine/timezone, since the clocks go back one hour at the end of October, the net effect is to add six hours, as opposed to seven
Very probably. In the case of my machine/timezone, since the clocks go back one hour at the end of October, the net effect is to add six hours, as opposed to seven
ASKER
The funny thing is that not all date/time combinations on this day have the problem, only a few. I would expect a similar behaviour for all...
>>not all date/time combinations on this day have the problem
Can you post an example that doesn't?
Can you post an example that doesn't?
ASKER
I'll post an example tomorrow, I am no longer at work ;-)
Anyway, colr__, CEHJ and RoyalNepal; thanks for your answers so far!
Anyway, colr__, CEHJ and RoyalNepal; thanks for your answers so far!
Mr. barrel,
as far as i understand...
SET METHOD:
lets say 07:00:00 is the current time..
and u do... calendar.set(Calendar.HOUR , 9);
now the current time is... 09:00:00
ADD METHOD:
lets say 07:00:00 is the current time.
and u do... calendar.add(Calendar.HOUR , 9);
current time will be 7 + 9 = 16 or 4...
whatever is the other difference....it might be because of time/regional difference...i am just guessing....:)
thanks
roy
as far as i understand...
SET METHOD:
lets say 07:00:00 is the current time..
and u do... calendar.set(Calendar.HOUR
now the current time is... 09:00:00
ADD METHOD:
lets say 07:00:00 is the current time.
and u do... calendar.add(Calendar.HOUR
current time will be 7 + 9 = 16 or 4...
whatever is the other difference....it might be because of time/regional difference...i am just guessing....:)
thanks
roy
ASKER
Actually, I receive two fields from the database which I combine into one GregorianCalendar (user requirements, I cannot help it ;-)
So; the first field is converted to a java.util.Date, no time is set (equal to 00:00:00). Additionally I have a java.sql.Time field which has no date.
So I know that I always start with hour => 0, minutes =>0 and seconds => 0 for the date. This date is used to initially set the time in the calendar, afterwhich I would like to add.
So; the first field is converted to a java.util.Date, no time is set (equal to 00:00:00). Additionally I have a java.sql.Time field which has no date.
So I know that I always start with hour => 0, minutes =>0 and seconds => 0 for the date. This date is used to initially set the time in the calendar, afterwhich I would like to add.
Couple of things to check I think:
1. hour => 0 etc. Do you mean hour == 0 (equals zero) ? I think you do.
2. How do you know that is true? java.util.Date has no concept of timezone, daylight saving or anything. The only time these matter is when you construct the Date from something else or convert a date into something else.
3. Assuming your Date is correct and the hour mins and secs *are* zero, we turn to the Calendar.
After doing calendar.setTime(theDate); What is calendar.getTimeInMillis() ?
Does this equal your original 1130623200000L ?
If not, then the Calendar has decided to set a time? (I suspect that will be OK)
4. After setting the hour, mins, secs, what is calendar.getTimeInMillis() in the two cases?
Again, trying to find if the Calendar is setting the time in the same way in both cases.
I suspect a difference may appear here. If so, we need to find out why.
5. Just for completeness, what is calendar.getTimeZone() ?
1. hour => 0 etc. Do you mean hour == 0 (equals zero) ? I think you do.
2. How do you know that is true? java.util.Date has no concept of timezone, daylight saving or anything. The only time these matter is when you construct the Date from something else or convert a date into something else.
3. Assuming your Date is correct and the hour mins and secs *are* zero, we turn to the Calendar.
After doing calendar.setTime(theDate);
Does this equal your original 1130623200000L ?
If not, then the Calendar has decided to set a time? (I suspect that will be OK)
4. After setting the hour, mins, secs, what is calendar.getTimeInMillis()
Again, trying to find if the Calendar is setting the time in the same way in both cases.
I suspect a difference may appear here. If so, we need to find out why.
5. Just for completeness, what is calendar.getTimeZone() ?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Ok, thanks for the explanation. Things are much clearer. Lets say you're at midmight, close your eyes for 4 hours (and passed the daylightsaving moment), you will find that it is 3 in the morning and not four. Pretty simple actually ;-)
> So, using add() involves no daylight saving in the calculation. using set() does involve daylight saving in the calculation.
> This would lead to a one hour difference.
You probably mean the other way around?
> So, using add() involves no daylight saving in the calculation. using set() does involve daylight saving in the calculation.
> This would lead to a one hour difference.
You probably mean the other way around?