1

Let's say that my device is in Australia (GMT+10:00).

I have a date "2016-04-22T17:45:00+02:00" received from an API.

I want to display it nicely in the original time zone (GMT+02:00).

So, I used SimpleDateFormat with "yyyy-MM-dd'T'HH:mm:ssZZZZZ".

String date = "2016-04-22T17:45:00+02:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ");
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(date));

But unfortunately, I can't find a clean way to display the date:

sdf.format(cal.getTime());

uses the device time zone.

So I parsed "manually" the date to extract the time zone to set it in the calendar.

cal.setTimeZone(TimeZone.getTimeZone("GMT" + date.substring(date.length() - 6, date.length())));

But it doesn't seems to do the trick.

How can I do this?

ldemay
  • 500
  • 7
  • 22
  • 2
    what is your original time zone format ?? – Bajirao Shinde Apr 20 '16 at 07:17
  • @ldemay: Could you try this (Java8)?DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZZZZ", Locale.ENGLISH); System.out.println(ZonedDateTime.parse("2016-04-22T17:45:00+02:00", dtf)); Also you receive data as +02:00 from your API always? – Unknown Apr 20 '16 at 07:19
  • @BajiraoShinde The date from API is GMT+02:00. My device is in GMT+10:00. I want to print the date in GMT+02:00. – ldemay Apr 20 '16 at 07:21
  • @Unknown I unfortunately can't use Java 8 yet. Thanks for your help anyway! – ldemay Apr 20 '16 at 07:22
  • @Unknown No, the API dates can be in any time zone. – ldemay Apr 20 '16 at 07:22
  • 1
    @ldemay The bulk of the functionality of the [java.time](http://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) framework built into [Java 8](https://en.wikipedia.org/wiki/Java_version_history#Java_SE_8) has been [back-ported to Java 6 & 7](http://www.threeten.org/threetenbp/) and [to Android](https://github.com/JakeWharton/ThreeTenABP). I *strongly* recommend avoiding the old date-time classes. Some reading on the subject in Stack Overflow should soon convince you. – Basil Bourque Apr 20 '16 at 19:45

2 Answers2

5

Time Zone = Offset + Rules

in the original time zone (GMT+02:00).

No, incorrect. The text GMT+02:00 represents an offset-from-UTC, not a time zone. A time zone is an offset plus a set of rules for handling anomalies such as Daylight Saving Time (DST).

A time zone is named in the format of continent/region such as America/Montreal or Asia/Kolkata. Always use these proper names. Never the 3-4 abbreviations seen in mainstream media; these are neither standardized nor unique.

UTC is the new GMT, in practical terms.

Avoid old date-time classes

The old date-time classes bundled with the earliest versions of Java have proven to be poorly designed, confusing, and troublesome. Avoid them. These classes were supplanted by the highly successful Joda-Time library and its successor the java.time framework.

The java.time framework is built into Java 8 and later. Much of its functionality was back-ported to Java 6 & 7 in the ThreeTen-Backport project, and further adapted to Android in the ThreeTenABP.

Learn more at the Oracle Tutorial.

OffsetDateTime

The input string has only an offset-from-UTC, not a full time zone. So we use the OffsetDateTime class to represent this kind of value.

Your input string is fortunately in standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing/generating textual representations of date-time values. So we can directly parse without bothering to define a formatting pattern.

String input = "2016-04-22T17:45:00+02:00";
OffsetDateTime odt = OffsetDateTime.parse( input );

Call OffsetDateTime::toString() to generate a string in the same format.

String output = odt.toString(); // ISO 8601 formatted string.

Instant

Programmers should not be thinking in these kind of local date-times. Generally you should do your business logic, database storage, and data-exchange all in UTC.

In java.time, an Instant represents a moment on the timeline in UTC with a resolution in nanoseconds. We can extract an Instant from our OffsetDateTime.

Instant instant = odt.toInstant();

ZonedDateTime

Always better to use a time zone than just an offset because of the rules for handling anomalies such as Daylight Saving Time.

You can easily adjust either an Instant or an OffsetDateTime into a time zone by applying a ZoneId to get a ZonedDateTime. For more discussion, see my longer answer and diagram on the general topic of converting/adjusting between these classes.

ZoneId zoneId_Montreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId_Montreal );

…or…

ZonedDateTime zdt_Montreal = odt.atZoneSameInstant( zoneId_Montreal );

Be aware that when applying a time zone you may see the time-of-day and even the date change. Adjustments may need to be made according to that zone’s rules to accommodate Daylight Saving Time (DST) or other issues.

You can adjust further into other time zones. You mention Australia. That country has many time zones, so you must choose which is appropriate to you (or your user) as they may have different rules either now or in the past or future.

ZoneId zoneId_Melbourne = ZoneId.of( "Australia/Melbourne" );
ZonedDateTime zdt_Melbourne = zdt_Montreal.withZoneSameInstant( zoneId_Melbourne );

You will notice when calling ZonedDateTime::toString that the method extends the standard ISO 8601 format by appending the name of the time zone in square brackets.

To generate strings in other formats, search Stack Overflow for topics of java.time.format and DateTimeFormatter. The ofLocalized… methods along with a Locale can automatically localize the formatting including translating human language day/month names, and following cultural norms for order of elements, period-versus-comma, and so on.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

As I can see Date object has no information about timezone. So a way but not the best can be parsing timezone from date string and set it to SimpleDateFormat. Something like:

String date = "2016-04-22T17:45:00+02:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ");
Calendar cal = Calendar.getInstance();

// tz is +02:00
String tz;
if (date.contains("+"))
    tz = date.substring(date.indexOf("+"));
else
    tz = date.substring(date.lastIndexOf("-"));

sdf.setTimeZone(TimeZone.getTimeZone("GMT" + tz));
System.out.println(sdf.format(cal.getTime()));
alpert
  • 4,500
  • 1
  • 17
  • 27
  • Your way of parsing the tz is sexier than mine, but I hoped the framework could answer this problem without any "tricks". Thanks EDIT tz can be "+" or "-" – ldemay Apr 20 '16 at 08:24
  • @Idemay I updated my answer based on your comment. I dont know and could not find and easier way. Ofcourse that doesnt mean there is not any. – alpert Apr 20 '16 at 08:37