Java Calendar inconsistent results - java

I have searched for the answer to this, but cannot seem to find one. Can someone explain why the following code does not give me the 1 of each month, but jumps to the 31 for some months? It is for a report event that needs to determine the next month's date.
DateFormat formatter = new SimpleDateFormat("dd-MMM-yy");
Calendar cal = Calendar.getInstance( TimeZone
.getTimeZone( "America/Los_Angeles" ) );
DateFormat formatter = new SimpleDateFormat("dd-MMM-yy");
Date date;
try
{
date = (Date)formatter.parse("01-JUN-12");
cal.setTime(date);
//cal.set(2012, 05, 01);
long now = new Date().getTime();
int frequency = 1;
System.out.println("Current calendar time=" + cal.getTime().toString()) ;
while (cal.getTime().getTime() < now)
{
cal.add( Calendar.MONTH, frequency );
System.out.println("In loop - current calendar time=" + cal.getTime().toString()) ;
}
}
catch (ParseException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
The output is:
Current calendar time=Fri Jun 01 00:00:00 EDT 2012
In loop - current calendar time=Sun Jul 01 00:00:00 EDT 2012
In loop - current calendar time=Tue Jul 31 00:00:00 EDT 2012
In loop - current calendar time=Fri Aug 31 00:00:00 EDT 2012
In loop - current calendar time=Mon Oct 01 00:00:00 EDT 2012
In loop - current calendar time=Wed Oct 31 00:00:00 EDT 2012
Notice how it jumps to 31, then back to 1. If I use Calendar.set() instead, the output is correct:
Current calendar time=Fri Jun 01 15:14:26 EDT 2012
In loop - current calendar time=Sun Jul 01 15:14:26 EDT 2012
In loop - current calendar time=Wed Aug 01 15:14:26 EDT 2012
In loop - current calendar time=Sat Sep 01 15:14:26 EDT 2012
In loop - current calendar time=Mon Oct 01 15:14:26 EDT 2012
In loop - current calendar time=Thu Nov 01 15:14:26 EDT 2012
This seems like it is either 1) A bug with the Calendar API, or 2) a lack of understanding of how the Calendar API works. In either case, I just want the next month (same day), unless of course there is a problem with certain months and days. But the above scenario is puzzling me. This does not happen with any other day of the month, only with the 1st.

It's a timezone issue. Replace your existing setup lines with the following, so that the Calendar and the Formatter are both using the same timezone:
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
formatter.setTimeZone(tz);
Calendar cal = Calendar.getInstance(tz);
and it all works fine:
Current calendar time=Fri Jun 01 08:00:00 BST 2012
In loop - current calendar time=Sun Jul 01 08:00:00 BST 2012
In loop - current calendar time=Wed Aug 01 08:00:00 BST 2012
In loop - current calendar time=Sat Sep 01 08:00:00 BST 2012
In loop - current calendar time=Mon Oct 01 08:00:00 BST 2012
In loop - current calendar time=Thu Nov 01 07:00:00 GMT 2012
You may want to replace the toString() calls with formatter.format() calls so that the output is in the right timezone too (it might look OK to you if you are in EDT, but I'm in the UK timezone, as you can see).

Instead of just cal.add( Calendar.MONTH, frequency );, try this:
cal.add(Calendar.MONTH, frequency);
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));

You are printing the time in the system default time zone. Use formatter to display it.
Set the same time zone for the formatter:
DateFormat formatter = new SimpleDateFormat("dd-MMM-yy");
formatter.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
And use it to display the time:
while (cal.getTime().getTime() < now) {
cal.add(Calendar.MONTH, frequency);
System.out.println("In loop - current calendar time=" + formatter.format(cal.getTime()));
}

From Javadoc Calendar
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 or other
constraints, such as time zone offset changes, 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 GregorianCalendar.
So in your case considering the time that you have set if calendar API add month to Jul then it is possible that it is getting overflown more than a month so it is being adjusted back Jul Midnight

Related

Android timezone bug really wierd

Anyone can tell me that where the code here give different results?
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1477785600000l);
cal.add(Calendar.DAY_OF_MONTH, 1);
System.out.println(cal.getTime());
System.out.println(cal.getTimeInMillis());
Calendar cal1 = Calendar.getInstance();
cal1.setTimeInMillis(1477785600000l);
cal1.add(Calendar.HOUR, 24);
System.out.println(cal1.getTime());
System.out.println(cal1.getTimeInMillis());
It works fine server-side but give different results when run on android platform.
You should use Calendar.HOUR_OF_DAY instead of Calendar.HOUR.
Like this:
cal1.add(Calendar.HOUR_OF_DAY, 23);
Are you using the same calendar instance to compare the equality of results?
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1477785600000l);
//add 1 day to the date
cal.add(Calendar.DAY_OF_MONTH, 1);
Log.e("first time", "" + cal.getTime());
Log.e("second time", "" + cal.getTimeInMillis());
//reset the calendar to the instance value removing the day added before
cal.add(Calendar.DAY_OF_MONTH, -1); //or you can use cal.setTimeInMillis(1477785600000l);
//add 24 hours to the base calendar value
cal.add(Calendar.HOUR, 24);
Log.e("third time", "" + cal.getTime());
Log.e("fourth time", "" + cal.getTimeInMillis());
And i'm obtaining the same values in the Android Monitor output
E/first time: Mon Oct 31 02:00:00 CET 2016
E/second time: 1477875600000
E/third time: Mon Oct 31 02:00:00 CET 2016
E/fourth time: 1477875600000
Just a copy of Thomas's comment.
It's the right answer and thank you all
Keep in mind that 1 day is not necessarily equal to 24 hours, i.e. when daylight saving is involved. As an example (not correct, just to illustrate the point) if I'd add 1 day to Oct 31st 2:00 I'd expect to get Nov 1st 2:00, but if I add 24 hours and the dst switch happens at that time I could get Nov 1st 3:00 (or so). - What I mean is that if you add 1 to the "day" field the hour is not changed but if you add 24 to the "hour" field you get a calculation of the day as well (roll over) which might include dst.
Please look into the Cal.add() method. In the first instance you add month and in the second instance you add hour. Change them and it will work fine.
Please see the documentation link: https://developer.android.com/reference/java/util/Calendar.html#getDisplayNames(int, int, java.util.Locale)
You need to use HOUR_OF_DAY for 24hr format. HOUR is HOUR is used for the 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the HOUR is 10 not 22.

adding date in calendar instance time zone is changing from EST TO EDT in android

I am adding a date in a calendar instance to check dst while adding a date eg 08-03-2014 to 09-03-2014 time zone is changing from EST TO EDT. The day light time is returning false.
TimeZone tz = TimeZone.getTimeZone("us/alaska");
Calendar c = Calendar.getInstance();
c.setTimeZone(tz);
c.add(Calendar.DAY_OF_MONTH, 1);
checkDayLightTime = tz.inDaylightTime(c.getTime());
System.out.println("current get time"+c.getTime());
System.out.println("checkDayLightTime"+checkDayLightTime);
03-08 02:59:58.505: INFO/System.out(12092): current get timeSun Mar 09 03:59:58 EDT 2014
03-08 02:59:58.505: INFO/System.out(12092): checkDayLightTimefalse
There is nothing wrong with you result EDT means that EST are currently in daylight. Actually Mar 08 is still in standard time and Mar 09 is in daylight saving time.
Some facts about EST:
Only some locations are currently on EST, because most places in this time zone are currently on Daylight Saving Time.
Locations that are on EST part of the year are currently on EDT (Eastern Daylight Time).

Strange behavior of Date/Calendar

I just want to create a method that sets the Date to time "23:59:59.999" of the same day. So I made this:
public static Date date235959(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
c.set(Calendar.HOUR, 23);
c.set(Calendar.MINUTE, 59);
c.set(Calendar.SECOND, 59);
c.set(Calendar.MILLISECOND, 999);
//c.set(Calendar.AM_PM, Calendar.PM);
return c.getTime();
}
When I run:
Date d = new Date();
d=date235959(d);
System.out.println(d.toString());
d=date235959(d);
System.out.println(d.toString());
I expected
Tue Sep 17 23:59:59 BRT 2013
Tue Sep 17 23:59:59 BRT 2013
But the output was
Tue Sep 17 23:59:59 BRT 2013
Wed Sep 18 11:59:59 BRT 2013
Why is that happened and how can I fix it?
The Calendar.HOUR is used for the 12-hour clock, use Calendar.HOUR_OF_DAY instead or put correct value for 12-hour clock: c.set(Calendar.HOUR, 11);
Use JodaTime instead of Java Calendar. It is the way more user friendly.
All Joda Time date/time objects are built on top of a long timestamp, so it is cheap to create those objects from a long.
In Joda Time ver 2.1 creating a date/time object from date/time components (year, month, day, hour, min, sec) is ~3.5 time slower than
the same operation for JDK GregorianCalendar.
Date components addition/subtraction is 3.5 times slower in Joda Time rather than in GregorianCalendar. On the contrary, time
components operations are about the same 3.5 times faster than
GregorianCalendar implementation.
Date/time parsing is working at about the same speed as in JDK SimpleDateFormat. The advantage of Joda parsing is that creating a
parser – DateTimeFormatter object is extremely cheap, unlike an
expensive SimpleDateFormat, so you don’t have to cache parsers
anymore.
http://java-performance.info/joda-time-performance/

wrong result in date difference in android

I want to perform a date operation in my android app. What I want is to subtract two dates and get the result. But subtraction leads to the wrong result whenever I change the time zone to central daylight time.
I use the following code to find the difference between the two dates.
Long lDateDiff = dtCycleDay.getTime() - m_dtHistory[0].getTime();
lDateDiff = lDateDiff / (1000 * 60 * 60 * 24);
Here in m_dtHistory[0], the date stored is Thu Mar 01 00:00:00 CST 2012.
And in my dtCycleDay variable the date changes from Thu Mar 01 00:00:00 CST 2012, Thu Mar 02 00:00:00 CST 2012, Thu Mar 03 00:00:00 CST 2012... and so on.
Now up to Thu Mar 11 00:00:00 CST 2012, the subtraction result is fine, but when the date changes to Thu Mar 12 00:00:00 CDT 2012, the CST changes to CDT and it show wrong subtraction result.
Why this happens and these happen only when I change the time zone to Central Daylight Time or pacific Daylight Time.
What do you mean by the "wrong" subtraction result?
My guess is that the result is 23 hours or 25 hours- which is exactly what I'd expect when a daylight transition occurs, as the intervening day is longer or shorter in terms of elapsed time. The "longer" day won't be relevant when dividing by 24, but the shorter one will... you're assuming that every day has 24 hours, and that you can therefore count the number of days by dividing the elapsed milliseconds by "the number of milliseconds in 24 hours". That doesn't work due to varying day lengths.
Don't forget that a Date value is purely an instant in time. It doesn't know about calendars or time zones... if you want to know the difference in "local" dates and times (where midnight to midnight is always 24 hours), I'd suggest using Joda Time instead... Date and Calendar don't really do that for you.
If the real problem you're describing is the time zone changing at the wrong date, that's a different matter entirely, and could be due to various different causes. For one thing, you should show exactly which time zone you're talking about: the abbreviations are ambiguous, whereas the tzdb names (e.g. "Europe/Paris") aren't.

Java Calendar set time to 12am of previous day in UTC

Can someone explain why or if this code is wrong?
// main
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
System.out.println(calendar.getTime());
calendar.add(Calendar.DATE, -1);
System.out.println(calendar.getTime());
calendar.set(Calendar.HOUR_OF_DAY, 0);
System.out.println(calendar.getTime());
It produces:
Fri Jan 28 15:27:35 EST 2011
Thu Jan 27 15:27:35 EST 2011
Wed Jan 26 19:27:35 EST 2011
Am I missing something obvious? I expect to see something like Thu Jan 27 00:27:35 EST 2011
Thanks.
You're printing it out in the default time zone, not UTC. Although your calendar knows the time zone you're interested in, the java.util.Date returned by getTime() doesn't... and Date.toString() uses the system time zone.
Given that you specified in the subject that you wanted 12am in UTC, why would you expect to see Thu Jan 27 00:27:35 EST 2011? EST isn't the same as UTC.
EDIT: As always, I'd just like to point out that Joda Time is generally a much nicer API to use for date/time arithmetic in Java. You're currently getting the right answer, but I'd still recommend moving to Joda :)
EST is UTC - 5 hours, so 19:27 EST corresponds to 00:27 UTC. It seems logical to me.
Use a date format with a UTC locale to display your calendars, instead of using your default locale.
For UTC calculations (only) you might find using long is simpler.
long time = System.currentTimeMillis();
// yesterday at 12:00:00.000 am.
long yesterday = (time / 86400000 - 1) * 86400000;

Categories

Resources