1

I cannot see why this code is failing:

@Test
public void test() {
    final SimpleDateFormat sdf= new SimpleDateFormat("yyyyMMddHHmm");
    try {
        sdf.setLenient(false);
        Date d = sdf.parse("202003290230");
    } catch (ParseException e){
        e.printStackTrace();
    }
}

I get the exception java.text.ParseException: Unparseable date.

If I set sdf.setLenient(true) then it works, but the time in the object Date returned is '03:30' and not '02:30'.

Can someone explain me what's going on in here? Thanks.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
maqjav
  • 2,310
  • 3
  • 23
  • 35
  • 8
    Daylight Saving Time. On 2020-03-29 the clock jumped a hour forward from 1:59 to 3:00 so that there never was any time 2:xx – OH GOD SPIDERS Nov 25 '20 at 10:43
  • You have to be kidding me! did they change the time that day? This was making me crazy! I didn't think of that. Thanks! – maqjav Nov 25 '20 at 10:44
  • hahaha this post just made my day. I can totally understand your frustration, bro! :)) – MehranB Nov 25 '20 at 10:45
  • I wasted two hours trying to figure this out, and the OH MIGHTY GOD SPIDERS saw it in 1 minute. ;) – maqjav Nov 25 '20 at 10:49
  • 3
    I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `LocalDateTime` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Nov 25 '20 at 15:38
  • And never swallow exceptions, especially not in tests. Or in production code. Or anywhere else. – Robert Nov 25 '20 at 15:42

1 Answers1

1

As OH GOD SPIDERS noted in a comment your real problem is that that time doesn’t exist in you default time zone because of the spring forward, the transition to summer time (DST).

java.time

I recommend that you use java.time, the modern Java date and time API, for your date and time work. The short-sighted answer is: use LocalDateTime from java.time.

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmm");
    String dateTimeString = "202003290230";
    LocalDateTime ldt = LocalDateTime.parse(dateTimeString, formatter);
    System.out.println(ldt);

Output is:

2020-03-29T02:30

A LocalDateTime is a date and time without time zone. So it doesn’t discover that the time doesn’t exist in your time zone. The result is 2:30 as in the string.

Detecting a non-existing time

It seems you’re in a Central European time zone or some other time zone where summer time began on the last Sunday in March, and the clocks were turned forward from 2 to 3 (AM). So there was no 2:30. Supposing that you want to know, you may do:

    ZoneId zone = ZoneId.of("Europe/Paris");
    ZonedDateTime zdt = ldt.atZone(zone);
    if (zdt.toLocalDateTime().equals(ldt)) {
        System.out.println("The time " + zdt + " exists");
    } else {
        System.out.println("The time " + ldt + " does not exist in " + zone);
    }

The time 2020-03-29T02:30 does not exist in Europe/Paris

java.time too gives you 3:30 instead of 2:30 when given a time in the spring gap. So when converting back from ZonedDateTime to LocalDateTime in this case we don’t get the same time again, which we use for detecting the non-existing time.

I further recommend that you use ZonedDateTime for past dates and times, not LocalDateTime.

Java 6?

This project is made with Java6 and the company doesn't want to update it, …

java.time has been backported, and I have tested the code above with the backport, ThreeTen Backport, see the link at the bottom.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310). I’m unsure whether the very latest release of ThreeTen Backport works with Java 6 or only with Java 7(+). If this is an issue, go back a few releases and find one that works with Java 6 too.
  • On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.

Don’t use SimpleDateFormat

The date and time classes you were trying to use, Date and SimpleDateFormat, are poorly designed and long outdated. In your case they showed a behaviour that depends on a time zone that isn’t present in the code at all, which is quite confusing. I recommend that you don’t use those classes.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Thanks for your comment. This project is made with Java6 and the company doesn't want to update it, however in modern projects java.time is the way to go with Java8+. – maqjav Nov 27 '20 at 09:47
  • @maqjav You can uses java,time with Java 6 too. See my edit. – Ole V.V. Nov 28 '20 at 06:35
  • 1
    @maqjav If, at the end of 2020, your employer doesn’t want to upgrade from Java 6, you should be out looking for a new employer, not a new solution. – Abhijit Sarkar Nov 28 '20 at 06:40