-1

For certain input values though format and all things are correct, I am getting ParseException from SimpleDateFormat.parse(String input) method.

I'm in a scenario where I need to convert time from PST timezone to local timezone; it works almost all of the time for acceptable input except for 2013-03-10T02:00:00Z to 2013-03-10T02:59:59Z. It seems strange; I tried several JDKs and machines, but the result is the same, it throws

Method threw 'java.text.ParseException' exception.

My expectation is to parse this date properly and return non null date object instead of throwing exception.

Snippet to test this:

    public static void main(String[] args) throws Exception {
        System.out.println(getDateFromString("2013-03-10T02:59:59Z", "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH));
    }

    public static Date getDateFromString(String dateText, String format, Locale locale) {
        Date date = null;
        SimpleDateFormat simpleDateFormat = null;
        try {
            simpleDateFormat = new SimpleDateFormat(format, locale);
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
            //Supporting strict validation of date format
            simpleDateFormat.setLenient(false);
            date = simpleDateFormat.parse(dateText);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • 4
    The 'Z' at the end means Zulu or UTC - It can't be parsed as PST because it's not in PST. – ryanwebjackson Jan 30 '23 at 20:02
  • 3
    I strongly recommend that you do not use `Date`, `SimpleDateformat` and `TimeZone`. Those classes are poorly designed, `SimpleDateFormat` in praticulat notoriously troublesome, and all are fortunately long outdated. Use `Instant`, `ZoneId` and `ZonedDateTime`, all from [java.time, the modern java date and time API](https://docs.oracle.com/javase/tutorial/datetime/index.html). – Ole V.V. Jan 30 '23 at 20:29
  • 2
    The time 2013-03-10T02:59:059 did not exist in PST because of transition to summer time (DST). I know, that time is in UTC (denoted by the trailing `Z`), and UTC hasn’t got summer time, so it should not matter. But you told your formatter a lie, you told it it was in PST, and it believed you and therefore threw the exception. – Ole V.V. Jan 30 '23 at 20:38
  • Whatever PST is, Pitcairn Standard Time, Philippine Standard Time or Pacific Standard Time. Three letter time zone abbreviations are most often ambiguous, so do not use them in your code. Use for example America/Vancouver for Canadian Pacific Time. – Ole V.V. Jan 30 '23 at 20:41
  • Use `Instant.parse("2013-03-10T02:59:59Z")` to parse your string. After that you may convert it to any time zone you like. See the link in my first comment for how, and/or search. And I repeat: that string is *not* in PST, no matter which of the mentioned interpretations of PST you go by. – Ole V.V. Jan 30 '23 at 20:45
  • 1
    Also, ['Z' is not the same as Z](https://stackoverflow.com/a/67953075/10819573). – Arvind Kumar Avinash Jan 30 '23 at 21:13
  • 1
    If you really need a `Date`, use `new Date(Instant.parse("2013-03-10T02:59:59Z") .toEpochMilli())`. In the unlikely case that you really need to support Java 7, use `new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")`. This works for your use case, i.e. `new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").parse("2013-03-10T02:59:59Z") .equals(new Date(Instant.parse("2013-03-10T02:59:59Z").toEpochMilli()))` is `true`. – Holger Jan 31 '23 at 09:22

1 Answers1

2

tl;dr

Your parse attempt failed because you misinterpreted the input text. The resulting erroneous value represented a date and time in a particular time zone that never existed.

Instead, correctly parse your input, and adjust into a time zone, using java.time classes.

Instant
.parse( "2013-03-10T02:00:00Z" )
.atZone( ZoneId.of( "America/Los_Angeles" ) )
.toString()

See Ideone.com.

2013-03-09T18:00-08:00[America/Los_Angeles]

Your code

Never put quotes around the Z in a date-time formatting pattern. That says to expect but ignore vital information: an offset from UTC of zero hours-minutes-seconds.

You asked:

why am I getting an issue with current code?

As other commented, I assume the legacy date-time classes attempted to parse your input of xx while guessing the value PST meant the time zone America/Los_Angeles. This would have happened because (a) you told the formatter to ignore the actual intended offset of zero represented by that Z, and then you (b) told the formatter to assume a default zone of PST.

So your code defies the intentions of whomever sent you that input data. Instead of 2013-03-10 02:59:59 in UTC, you tried to parse a value of 2013-03-10 02:59:59 in America/Los_Angeles.

As others have commented, that moment never existed. At 2 AM on March 13, 2013 all the people using time zone America/Los_Angeles jumped their clocks forward to 3 AM. This jump is the “Spring Ahead” cutover for Daylight Saving Time (DST). That day of March 13th was only 23 hours long, not 24 hours. The 02:00-03:00 hour was excised.

So your parse attempted failed because your misinterpreted input was coincidentally found to be senseless.

Revised code

Use modern java.time classes. Never use the terrible legacy classes.

Your input is in standard ISO 8601 format. No need to define a formatting pattern.

Instant instant = Instant.parse( "2013-03-10T02:59:059Z" ) ;

instant.toString() = 2013-03-10T02:59:59Z

Adjust to a desired time zone.

PST is not a real time zone. Perhaps you meant the time zone used by much of the west coast of the United States mainland.

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

zdt.toString() = 2013-03-09T18:59:59-08:00[America/Los_Angeles]

Note the change in date as well as time-of-day.

See that code run.

If you must have a java.util.Date to interoperate with code not yet updated to java.time, use new conversion methods added to the old classes.

java.util.Date d = Date.from( instant ) ;  // A date-time as seen in UTC, an offset of zero hours-minutes-seconds. 

Always search Stack Overflow before posting. All this has been covered many times before. Search to learn more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • 1
    I agree that java Instant class will work, but why am I getting an issue with current code? It should work ideally. Is it true that one of the above comments states, _"It's transition time, thus it won't work"_? or is it the misfortune of being a legacy / obsolete class? – Risabh Gupta Jan 31 '23 at 07:34
  • 1
    @RisabhGupta See revised explanation of why your code failed in its parse attempt. – Basil Bourque Feb 01 '23 at 21:07