Debaprasad Jana
Debaprasad Jana

Reputation: 185

DateFormat format method doesn't display a parsed date to a particular TimeZone

I converted a date string to Date by SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(DateinString).
Here instead of converting to UTC it is converting to my Local TimeZone. I checked it by displaying this parsed date through format method of DateFormat.

So I have to re format it back to UTC.Now when I am trying to display this parsed date to UTC TimeZone through the same format method, it is still displaying in local TimeZone. Following is my code to format the parsed date to UTC-

Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
cal.setTime(alreadyParsedDateTime); // 
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(cal.getTime()));       

My sample date string is "2015-12-23T15:00:00-0800"
After parse -- alreadyParsedDateTime.toString():: Thu Dec 24 04:30:00 IST 2015
After parse -- System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(alreadyParsedDateTime)):: 2015-12-24T04:30:00

After the above mentioned re format of the parsed date to UTC -- System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(cal.getTime())):: 2015-12-24T04:30:00

Expected date format is:: 2015-12-23T23:00:00

I don't know why the format method not working in an expected way or there is any trick to do the same. Kindly help..

Upvotes: 1

Views: 1557

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 338181

tl;dr

Current moment in UTC.

Instant.now()        // Capture current moment in UTC.
    .toString()      // Generate string in standard ISO 8601 format.

2018-02-11T22:13:28.650328Z

Adjust into another time zone.

instant.atZone(      // Apply a `ZoneId` to `Instant` object to get a `ZonedDateTime` object.
    ZoneId.of( "Pacific/Auckland" )
).toString()

2018-02-12T11:13:28.650328+13:00[Pacific/Auckland]

Or capture current moment directly into that zone.

ZonedDateTime.now(   // Capture current moment as seen on the wall-clock time of the people in a particular region.
    ZoneId.of( "Pacific/Auckland" )
).toString()         // Generate string in standard ISO 8601 format, wisely extended by appending the name of the time zone in square brackets.

2018-02-12T11:13:28.650328+13:00[Pacific/Auckland]

Details

The Answer by Grodriguez is correct but outdated.

java.time

The modern approach uses the java.time classes that supplant the troublesome old legacy date-time classes.

Your input string complies with the ISO 8601 formatting standard. The java.time classes use these formats by default when parsing/generating strings. So no need to specify a formatting pattern.

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Capture the current moment in UTC.

Instant instant = Instant.now() ;  // Current moment in UTC.

To view that same simultaneous moment through the lens of a wall-clock time used by the people of another region (time zone), apply a ZoneId to get a ZonedDateTime object.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Note that we are working with smart objects here, not dumb strings. Do not conflate the date-time objects with mere strings that may represent their values textually.

If you want to generate a String in standard ISO 8601 format, call the toString method.

String outputA = instant.toString() ;
String outputB = zdt.toString() ;

To generate strings in other formats, use the DateTimeFormatter or DateTimeFormatterBuilder classes. Both are covered extensively on Stack Overflow, so search for more info.


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.

With a JDBC driver complying with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings or 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.

Upvotes: 0

Grodriguez
Grodriguez

Reputation: 21985

There are two different topics here; parsing and formatting.

1. Parsing

SimpleDateFormat.parse() will try to parse the timezone from the supplied date string. If the date string you are parsing does not include an explicit timezone, then the "default" timezone on the SimpleDateFormat object will be used. You can set the default time zone with the setTimeZone() method. Please see the API docs for SimpleDateFormat.parse() and DateFormat.setTimeZone() for reference.

Here is an example that shows how the parsing is influenced by the timezone set with setTimeZone():

    String dateString = "2015.12.10 13:58:18";

    SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
    sdf1.setTimeZone(TimeZone.getTimeZone("GMT"));
    Date date1 = sdf1.parse(dateString);

    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
    sdf2.setTimeZone(TimeZone.getTimeZone("EST"));
    Date date2 = sdf2.parse(dateString);

    // Shows that the parsing honours time zone -- will print:
    // Thu Dec 10 14:58:18 CET 2015 (original date was parsed as GMT)
    // Thu Dec 10 19:58:18 CET 2015 (original date was parsed as EST)
    System.out.println(date1);
    System.out.println(date2);

2. Formatting

Assuming that the date has been parsed correctly, then your problem is with the formatting. You need to set the timezone for the actual SimpleDateFormat object that you are using for formatting. I modified your code to do this and it will now print what you expet:

    Calendar cal = Calendar.getInstance();
    cal.setTime(alreadyParsedDateTime);
    SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    sdf3.setTimeZone(TimeZone.getTimeZone("UTC"));

    // Prints: 2015-12-23T23:00:00 for your example date string
    System.out.println(sdf3.format(cal.getTime()));

Upvotes: 2

Related Questions