SimpleDateFormat ignoring DST offset in Android - java

In Central Europe, the current time zone (as of 3rd October) is:
CEST / UTC+2
But when I create an instance of SimpleDateFormat in Android now ...
dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
... it returns CET / UTC+1 as the time zone. So it's ignoring the DST offset which must still be there at the moment. Why is this?
Furthermore, when using the (now deprecated) method getTimezoneOffset() of Date instances, it returns inconsistent results:
(new Date()).getTimezoneOffset() correctly returns -120 (2 hours) while dateTimeFormat.parse("2012-10-03T22:00:00.000+0000").getTimezoneOffset() returns -60 (1 hour).
How can this happen? Am I doing something wrong or is this a known bug?
Note: I've heard that there are libraries which offer better time calculations (e.g. Joda Time), and I've heard that quite often now ;) But using some workarounds, you can just as easily use the built-in Java time library.
And, of course, the timezone is correctly set on my machine.

I don't know if I have properly understood your use case, but from what I have understood when I try this code.
public static void main(String[] args) {
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String date="2012-10-03T22:00:00.000+0000";
try {
System.out.println(dateTimeFormat.getTimeZone().getDisplayName());
System.out.println("Today : "+new Date().toString()+ ", Timezone Offset :" +
+(new Date()).getTimezoneOffset());
System.out.println("Parsed Date : "+
dateTimeFormat.parse(date).toString()
+ ", Timezone Offset : "
+dateTimeFormat.parse(date).getTimezoneOffset());
} catch (ParseException e) {
e.printStackTrace();
}
}
I am getting an consistent Output i.e :
Central European Time
Today : Wed Oct 03 09:44:56 CEST 2012, Timezone Offset : -120
Parsed Date : Wed Oct 03 23:00:00 CEST 2012, Timezone Offset : -120

I have just switched to JODA with is great.
It also works good on Android with the comments in this link:
Android Java - Joda Date is slow
That make it run faster.

Related

Changing Java Timestamp format causes a change of the timestamp

I'm a bit puzzled regarding the Java timestamp formatting functions as they seem to change the timestamp by a few minutes.
My Pivotal CloudFoundry app writes a new entry into a PostgreSQL 9.4.5 database. Doing so, I let PostgreSQL generate and store a timestamp for that entry (within the SQL statement I use 'now()' for that particular column).
All that works fine so far. Problems arise when I read the entry with my app because I have to format the timestamp to ISO 8601 (company policy) and this seems to change the timestamp. I've used this code:
public String parseTimestamp(String oldDate) {
System.out.println("String oldDate: " + oldDate);
TimeZone timeZone = TimeZone.getTimeZone("Europe/Berlin");
SimpleDateFormat oldDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSS");
SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
newDateFormat.setTimeZone(timeZone);
Date tempDate = null;
try {
tempDate = oldDateFormat.parse(oldDate);
} catch (ParseException e) {
//TODO
}
System.out.println("tempDate before format(): " + tempDate);
String newDate = newDateFormat.format(tempDate);
System.out.println("tempDate after format(): " + tempDate);
System.out.println("String newDate: " + newDate);
return newDate;
}
Output:
String oldDate: 2018-06-18 13:07:27.624828+02
tempDate before format(): Mon Jun 18 13:17:51 CEST 2018
tempDate after format(): Mon Jun 18 13:17:51 CEST 2018
String newDate: 2018-06-18T13:17:51Z
As you can see, the timestamp changed from 13:07 to 13:17. All the other queried entries also show a difference, varying between ~2 to 10 minutes. However, when I re-run the query, each difference stays the same. OPs told me that all involved systems have synchronised time and I'm not sure if system time should play a role here at all.
Does someone know what is going on?
First, I was really puzzled and thought, you might have found some kind of bug in SimpleDateFormat. Your code can be reduced to the following lines to show the same behaviour:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSS");
String str = "2018-06-18 13:07:27.624828+02";
System.out.println(str);
System.out.println(format.parse(str));
Result:
2018-06-18 13:07:27.624828+02
Mon Jun 18 13:17:51 CEST 2018
The parsed Date object got ten additional minutes (and some seconds).
Taking a closer look reveals the problem - it is NOT a bug in JDK:
Your millisecond-part is 624828 - these are six(!) digits (not three). 624828 milliseconds are about 624 seconds, which are 10 minutes and 24 seconds.
The SimpleDateFormat correctly summed up this additional seconds and minutes.
What's wrong too: Your date format contains five digits for the milliseconds part.
Solution:
The (new) Java Time API can handle larger fractions of a second - and also convert easily between different time zones:
String str = "2018-06-18 13:07:27.624828+02";
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSx");
OffsetDateTime date = OffsetDateTime.parse(str, pattern);
System.out.println(date);
System.out.println(date.withOffsetSameInstant(ZoneOffset.UTC));
Result:
2018-06-18T13:07:27.624828+02:00
2018-06-18T11:07:27.624828Z
Your input date contains micro seconds but SimpleDateFormat supports only milli seconds (up to 3 digits). When parsing the value with the flag lenient enabled the complete 6 digits are evaluated as micro seconds. So at the end you have 624 seconds that are added to the date additionally.
You can try to use the SSSSSS pattern with DateTimeFormatter that has been introduced in Java 8.
But you may have further issues. Your code parses the input date without the time zone information +02 that is included at the end. You should add one letter X for the ISO8601 time zone format. When formatting the date for outputting you use letter 'Z' that indicates time zone UTC. But you set time zone CET (Berlin). So the output date is not in UTC. The correct ouput in UTC for the specified input date is:
2018-06-18 11:07:27Z

Calendar DATE field is not updated

I'm working on some code that takes care of timezone differences (in this case, converting a date from UTC to EST/EDT) and I noticed that I'm getting the incorrect DATE field from the Calendar variable.
Here are the log excerpts from the timezone change:
UTC time: Fri Nov 15 00:28:44 EST 2013
America/New_York time: Thu Nov 14 19:28:44 EST 2013
The code is correctly updating the time to the 14th, based on what shows up with Calendar.getTime(), but when I call Calendar.get(Calendar.DATE), I'm still getting 15 as the date.
Why are the fields not updating when the time itself is?
Code excerpt:
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
TimeZone fromTz = TimeZone.getTimeZone("UTC");
TimeZone toTz = TimeZone.getTimeZone("America/New_York");
jlog.info(fromTz.getID() + " time: " + cal.getTime().toString());
cal.setTimeZone(fromTz);
// Finds the difference between the two timezones based on their offset from UTC (in the case of the system timezone changing in the future).
long currentTime = System.currentTimeMillis();
int timeDifference = toTz.getOffset(currentTime) - fromTz.getOffset(currentTime);
cal.add(Calendar.MILLISECOND, timeDifference);
if (dst) { // Logic for determining whether or not the extra hour for DST is needed.
cal.add(Calendar.MILLISECOND, fromTz.getDSTSavings());
}
jlog.info(toTz.getID() + " time: " + cal.getTime().toString());
jlog.info(cal.getTime().toString() + " - " + cal.get(Calendar.DATE));
Output for the above code:
UTC time: Fri Nov 15 00:28:44 EST 2013
America/New_York time: Thu Nov 14 19:28:44 EST 2013
Thu Nov 14 19:28:44 EST 2013 - 15
NOTE: Please don't suggest that I use Joda-time. I'm just looking for an answer to this question as is.
If it's not solvable because Calendar/Date are terrible packages, that's fine - I'll just parse the date myself to get the correct values. Thanks in advance.
You haven't shown us enough code to know what's going on, but your output is very easy to explain: you're calling Date.toString() which always formats the instant in time using the system local time zone. The time zone in the Calendar object is irrelevant.
So it looks like your Calendar may be in UTC for example, in which case the day is 15.
Note that the first line of your log is clearly nonsense:
UTC time: Fri Nov 15 00:28:44 EST 2013
It's either UTC or it's EST. It can't be both.
It's not clear where your data comes from or exactly how you're dealing with it, but if you're manually adjusting the date/time by adding or subtracting parts, you're almost certainly doing it wrong. It's very important to understand that a java.util.Date doesn't have any notion of a time zone as part of its data - it's just an instant in time.
To format a Date in a particular time zone, you'd usually use a SimpleDateFormat and specify the time zone on that. For example:
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("The time in New York is " + format.format(new Date()));
EDIT: Now that we've seen your code, you should definitely not do things that way. You're adjusting the point in time, which isn't what you want - you only want to change your view on the same point in time, which can be achieved using Calendar.setTimeZone to change what's returned by Calendar.get, and using DateFormat.setTimeZone to change which time zone is used for parsing/formatting text.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdtUtc = ZonedDateTime.of(LocalDate.of(2013, 11, 15), LocalTime.of(0, 28, 44),
ZoneId.of("Etc/UTC"));
ZonedDateTime zdtNewYork = zdtUtc.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
// Custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
System.out.println(zdtNewYork.format(dtf));
}
}
Output:
2013-11-14T19:28:44-05:00[America/New_York]
Thu Nov 14 19:28:44 EST 2013
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
If I understand your question, you could do it with something like this -
Calendar c = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy",
Locale.ENGLISH);
formatter.setTimeZone(TimeZone.getTimeZone("UTC")); // <-- Set the timezone on the
// DateFormat
/* Your input date/time */
c.setTime(new GregorianCalendar(2013, 10, 15, 0, 28, 44).getTime());
System.out.println(formatter.format(c.getTime()));
c.setTimeZone(TimeZone.getTimeZone("EST"));
System.out.println(c.getTime());
The output of this code is
Fri Nov 15 05:28:44 UTC 2013
Fri Nov 15 00:28:44 EST 2013

Converting unix timestamp to date in Android emulator

I have a timestamp I want to convert to a date. I tried this timestamp: 1336425840. This should be Mon, 07 May 2012 21:24:00 GMT, where GMT is the timezone the emulator should be set to. I tried this:
final Calendar c = Calendar.getInstance();
c.setTimeInMillis(1336425840*1000);
Date d = c.getTime();
Log.i("MyTag", "Hours: " + d.getHours());
The result is: Hours: 23.
So it seems like the returned date is computed according to GMT+2, which is the timezone set for my system. I expected g.hetHours() to return 21, since the emulator's timezone seems to be set to GMT.
Also, that timestamp results from reading the actual date in C using mktime, which seems to return the correct timestamp. But Java seems to refer to a different timezone. Am I doing anything wrong? Why isn't Mon, 07 May 2012 21:24:00 GMT returned?
I'm pretty sure 1336425840*1000 will give you a value outside the regular range of int. In fact, if you would print the full date of the Calendar object, you'll see it displays Thu Jan 08 23:56:50 GMT 1970, which explains the 23 hours you see.
Change the multiplication to: (note the L at the end)
c.setTimeInMillis(1336425840 * 1000L);
// Edit: easy to confirm:
System.out.println((1336425840 * 1000L > Integer.MAX_VALUE));
:)
You should use a DateFormat object, and then set the time zone with setTimeZone().

java.util.Date returning different dates in JDK 5 and JDK 6

The below code when run with JDK5(1.5.0_09) prints
Fri May 03 00:00:00 GMT 3912
5/3/12 5:30 AM
and when run with JDK6(1.6.0_23) prints
Fri May 03 00:00:00 IST 3912
5/3/12 12:00 AM
Obviously the difference is because of the timezone used then the Date object is created. But doesn't this cause problems for existing code when the JDK is upgraded? Is this behavior documented somewhere or am I missing something?
class TimeTest {
public static void main(String[] args) {
Date d = new Date(2012, 04, 3);
Locale l = new Locale("en", "US","");
DateFormat df= DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, l );
TimeZone t = TimeZone.getTimeZone("Asia/Calcutta");
df.setTimeZone(t);
System.out.println(d);
System.out.println(df.format(d));
}
}
The strange year 3192 is arising because that deprecated Date constructor assumes you are using a 2-digit year with 0 meaning 1900. It adds 1900 to the year number.
The difference in the timezones is not the fault of the Date constructor. Your code is using TimeZone.getTimeZone("Asia/Calcutta") to get the timezone. That method is documented as returning the GMT timezone if it doesn't recognize the timezone string. It would appear that Sun ADDED support for more timezones in Java 1.6. (Most people would view this as a good thing rather than as a portability concern.)
I haven't tried it, but the following should be sufficient to insulate yourself against using GMT when your requested zone id is unrecognised.
public TimeZone getZone(String id) {
TimeZone tz = TimeZone.getTimeZone();
if (!tz.getID().equals(id)) {
throw new IllegalArgumentException("unrecognized zone " + id);
}
return tz;
}
In summary, your code is broken in two respects:
It is using a deprecated constructor.
It is assuming that getTimeZone will understand all of your timezone Strings, and this is clearly not the case for Java 1.5.

Get server date problem

I have problem with getting server date (linux server). When I use linux 'date' command I get properly date value (real date). If I modify some file
on server, modify date is also properly (real date). But if i use java code System.out.println(new Date()) on server I get date with 1 hour difference
i.e. linux 'date' command result = Wed Sep 16 08:48:25 CEST, System.out.println(new Date()) result = Wed Sep 16 07:48:25 GMT+1
Is this linux configuration problem or wrong getting date using java.
Thanks
date --rfc-2822; date +%s
Wed, 16 Sep 2009 09:59:36 +0200
1253087976
System.out.println(new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").format(new Date()));
System.out.println(new Date().getTime() / 1000);
16 wrz 2009 09:00:33 +0100
1253088033
You must make sure you use the correct time zone before using Date (or Calendar, for that matter - wasn't Date deprecated?).
For instance:
/* Skipping the boring class def part. */
public static void main(String[] args) {
Date date = new Date();
DateFormat myDateFormat = new SimpleDateFormat();
TimeZone firstTime = TimeZone.getTimeZone(args[0]);
myDateFormat.setTimeZone(firstTime);
System.out.println("-->"+args[0]+": " + myDateFormat.format(date));
}
the argument then can be your desired time zone, for example "IST", "GMT", or whatever.
This is probably a timezone/daylight savings issue. Use:
java.util.Timezone.getDefault()
to see which timezone is Java configured to use and whether daylight savings apply or not.
I suggest you upgrade your Java installation. Your JRE likely doesn't have the latest daylight savings rules in place. Java gets the time since the epoch, and uses your current TZ setting to compute what the local time is. DST rules change from time to time, and both the operating system and the JDK need to be updated when this occurs.
Can you add the output of the following to your question:
# unix
date --rfc-2822; date +%s
# Java
System.out.println(new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").format(new Date()));
System.out.println(new Date().getTime() / 1000);
The should both output something like:
Wed, 16 Sep 2009 17:26:08 +1000
1253085968

Categories