简体   繁体   中英

Date format conversion from CST to GMT is not working

I have a date string in CST (24 Hours) and I want to convert it to GMT (12 Hours). I have a java method like below which works fine when my system time is Kolkata time. (System where I run the java method) But when my system is in Shanghai time, the GMT time comes incorrect.

String inputDate = "01-19-2017 06:01 CST";
SimpleDateFormat inputFormatter = new SimpleDateFormat("MM-dd-yyyy hh:mm Z");
parsedInput = inputFormatter.parse(inputDate);

// parsedInput -> Tue Jan 19 06:01:00 CST 2017   -> When system time is Shanghai time
// parsedInput -> Thu Jan 19 17:31:00 IST 2017   -> When system time is Kolkata time


SimpleDateFormat formatter = new SimpleDateFormat("MM-dd-yyyy hh:mm a Z");
TimeZone gmt = TimeZone.getTimeZone("GMT");
formatter.setTimeZone(gmt);
String formattedDate = formatter.format(parsedInput);

// formattedDate -> 01-18-2017 10:01 PM +0000   -> When system time is Shanghai time (Incorrect)
// formattedDate -> 01-19-2017 12:01 PM +0000   -> When system time is Kolkata time

Avoid pseudo time zones

The 3-4 letter time zone abbreviations such as CST are not actual time zones. They are not standardized. They are not even unique!

Your CST might be “China Standard Time” or might be “Central Standard Time” in the Americas, or might be something else. There is no way to know which one.

Another example: IST might mean “India Standard Time” or “Ireland Standard Time” or others.

Deciphering these pseudo-zones reliably is impossible. The Joda-Time library has a wise policy of refusing to even try. Unfortunately the java.time classes make a guess when parsing, but the result may not be the zone you expect.

So never use these useless pseudo-zones. Use a proper time zone name in the format of continent/region such as America/Chicago , Asia/Kolkata , Pacific/Auckland .

Avoid legacy date-time classes

You are using the troublesome old date-time classes that are now legacy, supplanted by the java.time classes.

Workaround

If you know all your inputs are intended for the same time zone, then lop off the pseudo-zone and process as a LocalDateTime , apply the intended zone as a ZoneId to produce a ZonedDateDate . From that you can extract an Instant for UTC time.

String input = "01-19-2017 06:01".replace( " " , "T" ) ;  // Insert a “T” to comply with standard ISO 8601 format used by default in java.time.
LocalDateTime ldt = LocalDateTime.parse( input );  // Lacks any concept of time zone or offset-from-UTC. So *not* an actual moment on the timeline.
ZoneId z = ZoneId.of( "America/Chicago" ); // Assuming “CST” meant this zone in North America.
ZonedDateTime zdt = ldt.atZone( z );  // Assign a time zone to determine an actual moment on the timeline. 
Instant instant = zdt.toInstant();  // Extract a value in UTC.

You may choose to see that same moment through the lens of the wall-clock time in India.

ZonedDateTime zdtKolkata = zdt.withZoneSameInstant( ZoneId.of( "Asia/Kolkata" ) ) ;

Never rely on default zone

Your JVM's current default time zone can be changed at any moment by any code in any thread of any app executing within that JVM. Since this can change at any moment you cannot rely on a certain value.

When you omit the optional argument for time zone, the date-time classes implicitly silently apply the current default time zone. So the solution is simple: Always specify the expected/desired time zone .

Notice how the code example above specifies the zone at every opportunity.

(Ditto for Locale , by the way. Specify explicitly rather than rely on current default.)

Your problem is the ambiguity of CST. In most cases SimpleDateFormat understands CST as Central Standard Time as you had expected. But when your computer is running Shanghai Time, this becomes the time zone of the formatter's calendar, and then it suddenly understands CST as China Standard Time, the same as Shanghai time.

Therefore Darshan Mehta's solution , setting inputFormatter 's time zone to something other than China Standard Time, works on my computer. I don't know why it didn't work on yours (I set it to TimeZone.getTimeZone("America/Chicago") to match the intended interpretation of CST).

The correct and good solution, though, is to avoid the three and four letter time zone abbreviations completely. Yours is just one example out of many where they cause trouble. If you can, give your input string with an explicit zone offset from UTC, such is never ambiguous:

    String inputDate = "01-19-2017 06:01 -0600";

Now your code works as expected no matter your computer's time zone setting. The Z in the pattern string you already have matches -0600 nicely.

All of this said, if you can use the Java 8 date and time classes, you can do yourself a favour of switching over to them. I hesitate to call them “Java 8 date and time classes” because they have also been backported to Java 6 and 7, so if you can live with a library dependency until you get to Java 8, you should have every chance. The newer classes are significantly more programmer-friendly and convenient to work with. A simple example to get you started:

    String inputDate = "01-19-2017 06:01 -0600";
    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm Z");
    ZonedDateTime parsedInput = ZonedDateTime.parse(inputDate, inputFormatter);

    OffsetDateTime gmtTime = parsedInput.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd-yyyy hh:mm a Z");
    String formattedDate = gmtTime.format(formatter);
    System.out.println(formattedDate); // prints 01-19-2017 12:01 PM +0000

Try setting the TimeZone to inputFormatter as well, eg:

SimpleDateFormat inputFormatter = new SimpleDateFormat("MM-dd-yyyy hh:mm Z");
inputFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));

If you don't specify the time zone, it takes the default value into account which is Asia/Shanghai in your case and hence, incorrect result.

You can reproduce it in your current system by replacing GMT with Asia/Shanghai in the above snippett

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM