0

I am trying to create a proper conversion method for my app which will get the input as PST and can convert it to CST or EST and also support the daylight saving.

Here is the problem. Check this below code and the output. I am simply converting my PST date to CST and EST and printing it. But in output CST and EST is same. there needs to be 1 hour of difference but it is not reflecting.

    System.out.println("CURRENT in PST : " + new Date());
    SimpleDateFormat utcDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    utcDateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
    System.out.println("convert in PST : " + utcDateFormat.format( new Date()));

    utcDateFormat.setTimeZone(TimeZone.getTimeZone("CST"));
    System.out.println("convert in CST : " + utcDateFormat.format(new Date()));

    utcDateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
    System.out.println("convert in EST : " + utcDateFormat.format(new Date()));

OutPut :

CURRENT in PST : Wed Jun 13 15:14:15 PDT 2018
convert in PST : 2018-06-13T15:14:15Z
convert in CST : 2018-06-13T17:14:15Z
convert in EST : 2018-06-13T17:14:15Z

So can any one please let me know why? And how I can do this conversion perfectly for all timezones of USA.

I used EST5EDT and it worked but don't know it will support when daylight saving start or ends. I can use JAVA 8.

user2367130
  • 125
  • 1
  • 2
  • 10
  • 1
    Fun fact: `PST` observes daylight savings; `EST` doesn't. You should maybe read [this](http://errorprone.info/bugpattern/ThreeLetterTimeZoneID) to understand more about why you shouldn't use three-letter time zone IDs. – Andy Turner Jun 13 '18 at 22:41
  • I recommend you avoid the `SimpleDateFormat` class. It is not only long outdated, it is also notoriously troublesome. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jun 14 '18 at 07:20
  • 1
    The `Z` denotes offset zero from UTC, so don’t hardcode it, and at least not when your offset is not zero (which it isn’t in the time zones you mention). Also don’t rely on three letter time zone abbreviations, they are not standardized and often ambiguous. Each of CST, EST and PST has multiple interpretations. – Ole V.V. Jun 14 '18 at 07:23

1 Answers1

3

tl;dr

how I can do this conversion perfectly for all timezones of USA.

Instant now = Instant.now() ;  // Capture current moment in UTC.
ZonedDateTime zdtLosAngeles = now.atZone( ZoneId.of( "America/Los_Angeles" ) ) ;
ZonedDateTime zdtChicago = now.atZone( ZoneId.of( "America/Chicago" ) ) ;
ZonedDateTime zdtNewYork = now.atZone( ZoneId.of( "America/New_York" ) ) ;
ZonedDateTime zdtGuam = now.atZone( ZoneId.of( "America/Guam" ) ) ;
ZonedDateTime zdtHonolulu = now.atZone( ZoneId.of(  "America/Los_Angeles" ) ) ;
ZonedDateTime zdtAnchorage = now.atZone( ZoneId.of( "America/Anchorage" ) ) ;
ZonedDateTime zdtIndianapolis = now.atZone( ZoneId.of( "America/Indiana/Indianapolis" ) ) ;
ZonedDateTime zdtPortOfSpain = now.atZone( ZoneId.of( "America/Port_of_Spain" ) ) ;
ZonedDateTime zdtPhoenix = now.atZone( ZoneId.of( "America/Phoenix" ) ) ;

… and so on through the list of the many time zones in the United States.

Date is UTC

"CURRENT in PST : " + new Date()

This is incorrect; this code is not behaving as you apparently are expecting. You may get a String such as Wed Jun 13 15:58:37 PDT 2018, or you may not.

A java.util.Date is always in UTC, by definition. Defined as a count of milliseconds since the epoch reference of first moment of 1970 in UTC. You generated output string may be in west coast time, but that is only by accident.

The confusing part is that the Date::toString method is unfortunately designed to inject the JVM’s current default time zone dynamically while generating a String to represent this Date object’s value. If your JVM happens to have a current default time zone of a zone such as America/Los_Angeles, you will get a string with a west coast US time-of-day. But then your results will vary at runtime should the default time zone be set otherwise, and your "CURRENT in PST:" label will be incorrect. And remember that the JVM’s current default time zone can be changed at any moment during runtime by any code in any thread of any app within the JVM.

The legacy date-time classes are riddled with such poor design choices. Avoid using these classes.

java.time

The modern approach uses the java.time classes rather than those troublesome old legacy date-time classes.

Instant replaces java.util.Date. 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).

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

Apply a time zone (ZoneId) to get a ZonedDateTime object. Same moment, same point on the timeline, but viewed through the wall-clock time used by the people of a certain region.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter pseudo-zones such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

As a shortcut, you can skip the Instant object by calling ZonedDateTime.now and passing a ZoneId.

ZonedDateTime zdt = ZonedDateTime.now( z ) ;

And how I can do this conversion perfectly for all timezones of USA.

Firstly, never use the pseudo-zones “PST”, “CST”, “EST” is discussed above. Use real time zones.

There are many more than three zones in the United States, such as America/Chicago, America/New_York, America/Fort_Wayne, Pacific/Honolulu, America/Puerto_Rico, and so on. Why so many? Because current and past practices have varied. For example, some places in the US opt out of the silliness of Daylight Saving Time (DST). Various places have various histories where the offset-from-UTC in that zone were changed by people at different points in their history.

Secondly, keep your time zone definitions up-to-date. Most software systems use a copy of tzdata (formerly known as Olson Database) published by IANA. Your host OS, your JVM implementation, and your database server, likely all have a copy of tzdata that must be kept up-to-date if the rules for any zone you care about change.

Never ignore zone/offset

"yyyy-MM-dd'T'HH:mm:ss'Z'"

Your formatting pattern made a dreadful choice in putting single-quote marks around the Z. That Z means UTC, and is pronounced Zulu. Your single-quotes tell the formatter to ignore that particular string as if it were meaningless. But it is not meaningless, it is vital information about your input data which you are choosing to ignore and discard.

Another thing… That particular format is defined by the ISO 8601 standard. The java.time classes use these standard formats by default when parsing/generating strings.

Instant.parse( "2018-01-23T12:34:56Z" )  // Parse standard ISO 8601 string into a `Instant` object.

instant.toString() // Yields "2018-01-23T12:34:56Z".

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
    "This is incorrect." The string produced is based on the JVM's default time zone; so if OP is in California (and in winter), then it would be PST. – Andy Turner Jun 13 '18 at 22:44
  • @AndyTurner I added text to address your point. If JVM’s current default time zone just *happens* to be set to a west coast time zone, her/his expected string will be produced. But at any moment any other code in that JVM may change the time zone, in case the resulting string will be mislabeled. Or the configuration of the JVM at startup may be later changed, in which case the resulting string will be mislabeled. So that code as written is not behaving as its author intended. – Basil Bourque Jun 13 '18 at 22:56