Android timezone bug really wierd - java

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.

Related

Can't convert time to GMT

My problem is that I want to convert the local time to GMT. I am able to convert the actual time and save it to Parse but the problem is that Parse applies its own:
Wed Feb 24 10:00:00 GMT+05:30 2016
This is the date that I am getting after converting to GMT00:00 but the problem is the GMT+05:30 that is actually false as my date is actually in GMT. Now when I put this date in the server it further decreases the time by 5:30 hrs. So how can we change this GMT+05:30 to GMT+00:00
If you are using java 8. you could utilize from the new time library.
As you tell it seems what you want, is to have a stamp in UTC which is GMT+00
more about time library here
This line:
System.out.println(Instant.now().toString());
gives
2016-02-25T17:54:55.420Z
Hope it makes thing more clear to you.
We'll start with the current local time.
Calendar cal = Calendar.getInstance(); // automatically produces and instance of the current date/time
As I understand it, your local date is accurate to GMT but your time is 5:30 ahead of actual GMT.
In order to subtract 5:30 from your local time you can perform the following.
cal.add(Calendar.HOUR, -5);
cal.add(Calendar.MINUTE, -30);
System.out.println(cal.getTime());
Conversely, if you would like to add to the time field, you can simply use:
cal.add(Calendar.HOUR, 5); // note I have removed the minus(-) symbol
cal.add(Calendar.MINUTE, 30); // note I have removed the minus(-) symbol
System.out.println(cal.getTime());

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/

Java Calendar: 1am switchover to standard time (from DST)

I have some code that uses Calendar.set() to return the beginning of the hour for a given date value. I encountered the following issue on Sunday Nov 4th, 2012 (Eastern Timezone - EDT to EST switchover):
public void testStartOfHourDST1() {
Calendar cal = Calendar.getInstance();
long time = 1352005200000L; // Nov 4, 2012, 1AM EDT
cal.setTimeInMillis(time);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
System.out.println(new Date(time));
System.out.println(new Date(cal.getTimeInMillis()));
System.out.println(System.getProperty("java.version"));
assertEquals(cal.getTimeInMillis(), time); // fails
return;
}
Ouput:
Sun Nov 04 01:00:00 EDT 2012
Sun Nov 04 01:00:00 EST 2012
1.6.0_35
Perhaps this is not the correct way to be using calendar, but running the same test for the next hour (or previous hour) works fine. Is this a JVM issue?
Thanks
It's not really an issue, in the sense that it is deterministic and doing what it was programmed to do. It's an issue if you would prefer that it pick the earlier of the two 1ams!
After changing fields on the Calendar the only information it has is "1am in US/Eastern". Well, your timezone had two 1ams that day, which one is it supposed to pick? The authors of OpenJDK made a decision that when presented with this ambiguity, they would always interpret it as the later one, in standard time. This comment is from java.util.GregorianCalendar OpenJDK 6:
// 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
// can be in standard or DST. Both are valid representations (the rep
// jumps from 1:59:59 DST to 1:00:00 Std).
// Again, we assume standard time.
If you print out the actual values of the numbers you will see cal.getTimeInMillis() has actually been changed by an hour from the value of time.
Getting the correct time zone is very important. For example, as I'm sure you are aware the system current time in milliseconds is measured from midnight on the 1st of January 1970. This is well documented. The Date constructor JavaDoc says:
public Date(long date)
Allocates a Date object and initializes it to represent the specified
number of milliseconds since the standard base time known as "the
epoch", namely January 1, 1970, 00:00:00 GMT.
which is fine, but makes the output of this program a little hard to understand at first:
import java.util.Date;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
public class Demo {
public static void main(String[] args) {
TimeZone tz = TimeZone.getTimeZone("Europe/London");
Date d = new Date(-3600000);
SimpleDateFormat df = new SimpleDateFormat("MMMM dd, yyyy HH:mm:ss.SSS z");
df.setTimeZone(tz);
System.out.println(String.format("%8dms -> %s",
Long.valueOf(d.getTime()) ,df.format(d)));
d.setTime(0);
System.out.println(String.format("%8dms -> %s",
Long.valueOf(d.getTime()) ,df.format(d)));
}
}
The output is:
-3600000ms -> January 01, 1970 00:00:00.000 GMT
0ms -> January 01, 1970 01:00:00.000 GMT
As you can see, the epoch is apparently displaced by an hour!
Except it is not. If you use the "GMT" time zone explicitly, all is well. The "Europe/London" time zone is simply tricky like that.
When working with Calendars, understand the time zone you are using or be caught out.

Java Calendar inconsistent results

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

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