Simpledateformat Parse Loses Timezone

SimpleDateFormat parse loses timezone

All I needed was this :

SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

SimpleDateFormat sdfLocal = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");

try {
String d = sdf.format(new Date());
System.out.println(d);
System.out.println(sdfLocal.parse(d));
} catch (Exception e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}

Output : slightly dubious, but I want only the date to be consistent

2013.08.08 11:01:08
Thu Aug 08 11:01:08 GMT+08:00 2013

Java DateFormat parse() doesn't respect the timezone

You're printing the result of calling Date.toString(), which always uses the default time zone. Basically, you shouldn't use Date.toString() for anything other than debugging.

Don't forget that a Date doesn't have a time zone - it represents an instant in time, measured as milliseconds since the Unix epoch (midnight on January 1st 1970 UTC).

If you format the date using your formatter again, that should come up with the same answer as before.

As an aside, I would recommend the use of Joda Time instead of Date/Calendar if you're doing any significant amount of date/time work in Java; it's a much nicer API.

SimpleDateFormat.parse() ignoring timezone?

Note: -06:00 is an offset, not a timezone - those 2 concepts are related, but they are different things (more on that below).


The problem with SimpleDateFormat and Calendar is that they use the system's default timezone, so even though you parse a date with a different offset (like -06:00), the resulting Calendar will have the default timezone (you can check what zone is by calling TimeZone.getDefault()).

That's just one of the many problems and design issues of this old API.

Fortunately, there's a better alternative, if you don't mind adding a dependency to your project (in this case, I think it's totally worth it). In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP to make it work (more on how to use it here).

To work with offsets, you can use the org.threeten.bp.OffsetDateTime class:

// parse the String
OffsetDateTime odt = OffsetDateTime.parse("2017-07-26T06:00-06:00");

This will parse all the fields correctly (date/time and offset). To get the offset value, similar to calendar.getTimeZone().getRawOffset(), you can do:

// get offset in milliseconds
int totalSeconds = odt.getOffset().getTotalSeconds() * 1000;

I had to multiply by 1000 because calendar returns the value in milliseconds, but ZoneOffset returns in seconds.

To convert this to another offset (+09:00), it's straightforward:

// convert to +09:00 offset
OffsetDateTime other = odt.withOffsetSameInstant(ZoneOffset.ofHours(9));

As I said, timezone and offset are different things:

  • offset is the difference from UTC: -06:00 means "6 hours behind UTC" and +09:00 means "9 hours ahead UTC"
  • timezone is a set of all the different offsets that a region had, has and will have during its history (and also when those changes occur). The most common cases are Daylight Saving Time shifts, when clocks change 1 hour back or forward in a certain region. All these rules about when to change (and what's the offset before and after the change) are encapsulated by the timezone concept.

So, the code above works fine if you're working with offsets and wants to convert to a different one. But if you want to work with a timezone, you must convert the OffsetDateTime to a ZonedDateTime:

// convert to a timezone
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("Asia/Tokyo"));
// get the offset
totalSeconds = zdt.getOffset().getTotalSeconds() * 1000;

The getOffset() method above will check the history of the specified timezone and get the offset that was active in that corresponding instant (so, if you take a date during DST, for example, the offset (and also date and time) will be adjusted accordingly).

The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.

You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().

You can also use the system's default timezone with ZoneId.systemDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.

SimpleDateFormat with timezone displaying dates in my timezone, how do I fix this?

You can use the modern java.time package instead and specially ZonedDateTime that handles time zones.

String str = "2019-12-20T00:00:00.000-05:00";
ZonedDateTime zonedDateTime = ZonedDateTime.parse(str);

And when showing it in the UI use DateTimeFormatter to convert it to a formatted string

DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; 

or with some custom format

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

which will give you for the 2 formats

System.out.println(formatter.format(zonedDateTime));

2019-12-20T00:00-05:00

2019-12-20 00:00

SimpleDateFormat not parsing IST date

Don't use Date or SimpleDateTime. Use the classes in the java.time package.

String date = "Mon, 05 Jul 2021 23:19:58 IST";

DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(
"EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
ZonedDateTime zdt = ZonedDateTime.parse(date,dateFormat);
System.out.println(zdt.format(dateFormat));

prints

Mon, 05 Jul 2021 23:19:58 GMT

EDIT

After perusing the java.time package I found that ZoneId.SHORT_IDS contained IST=Asia/Kolkata. So if one does the following:

ZonedDateTime zdt = ZonedDateTime.parse(date,dateFormat)
.withZoneSameLocal(ZoneId.of("Asia/Kolkata"));
System.out.println(zdt.format(dateFormat));

It prints

Mon, 05 Jul 2021 23:19:58 IST

SimpleDateFormat issue when parsing a String in ISO 8601 format

The date format passed to your SimpleDateFormat is "dd/MM/yy", while the date you are trying to parse is of the format "yyyy-MM-dd". Try this instead:

Date login = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ").parse("2017-05-16 06:24:36-0700");

As a side note, depending on which version of Java you are using, I would recommend using the new java.time package (JDK 1.8+) or the back port of that package (JDK 1.6+) instead of the outdated (no pun intended) Date and/or Calendar classes.

Instant login = Instant.from(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssZ").parse("2017-05-16 06:24:36-0700"));

SimpleDateFormat parse is changing time according to timezone

Java's java.util.Date and java.sql.Timestamp do not store timezone.

They always track time in UTC.

When parsing a date string that includes a timezone, the string is correctly parsed and adjusted from the given timezone to UTC.

When parsing a date string without timezone, the string is parsed in the JVM's default timezoneand converted to UTC, unless another timezone has been explicitly given to the date parser (commonly SimpleDateFormat).

When displaying (aka formatting) a Date/Timestamp, it will be shown in the JVM's default timezone, unless otherwise specified.

The Date/Timestamp objects cannot store a timezone, so they cannot remember what the original timezone was.

If you need that, use Java 8's ZonedDateTime.

java date parse exception while conveting UTC to local time zone

You have two mistakes in your code.

  1. As others already mentioned you have additional ' in your pattern around Z.
  2. You specify the pattern as dd-MM-yyyy but try to parse the date as yyyy-MM-dd.

Correct version:

DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = utcFormat.parse("2015-03-17 06:00:00 +0000");
utcFormat.setTimeZone(TimeZone.getDefault());
System.out.println(utcFormat.format(date));


Related Topics



Leave a reply



Submit