1

Could you any one point out why following example gives a parse exception. IDea is to find an invalid date like Feb 30

    String str = "20190310022817";

    SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
    sdf.setLenient(false);
    try {
        System.out.println(sdf.parseObject(str));
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
Arun Nair
  • 425
  • 3
  • 11
  • While validity checking is a good idea, don’t use `SimpleDateFormat` for the purpose. That class is notoriously troublesome and long outdated. Use `DateTimeFormatter` and `LocalDateTime`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Mar 20 '19 at 00:05

3 Answers3

2

The string "20190310022817" represents Sunday, March 10, 2019 at 2:28:17, which did not exist because of Daylight Saving Time, which in the USA took effect on Sunday March 10, 2019 at 2:00:00.

This means that the second following Sunday March 10, 2019 1:59:59 was Sunday March 10, 2019 3:00:00, so 2:28:17 did not exist on that date (nor did any other second during that hour).

You can either adjust the time represented in the string or recognize that this gap in time did not exist and handle the exception appropriately.

rgettman
  • 176,041
  • 30
  • 275
  • 357
2

tl;dr

LocalDateTime
.parse( 
    "20190310022817" , 
    DateTimeFormatter.ofPattern( "uuuuMMddHHmmss" )
)
.atZone(
    ZoneId.of( "America/Montreal" ) 
)

Result is 3 AM rather than 2 AM. Feature, not a bug, adjusting for DST.

2019-03-10T03:28:17-04:00[America/Montreal]

If your goal is to reject such invalid inputs rather than adjust them, see my Answer an another Question that explains the ResolverStyle enum: LENIENT, SMART, & STRICT.

Avoid legacy date-time classes

You are using terrible date-time classes that were supplanted years ago by the modern java.time classes.

Daylight Saving Time (DST)

As pointed out in the Answer by rgettman, some jurisdictions crazy enough to participate in Daylight Saving Time (DST) were doing their “Spring-ahead” jump on your given date of March 10 at the 2 AM hour. This was happening in most of the US & Canada, and maybe elsewhere. See Wikipedia about DST in the United States.

In these locations, there is no 2 AM hour. When the clock strikes 2 AM, the clock jumps instantly to 3 AM. The two o’clock hour never existed.

By the way, DST is not the only scheme by which the clock changes. Politicians around the world have shown a penchant for messing with the offset-from-UTC in their jurisdiction. For example, see North Korea, Venezuela, Turkey, and Russia in recent years. And now some states with the US are in the process of choosing to stop the DST nonsense, though some are thinking of staying on DST permanently. The point is, for robust handling of date-times, regardless of current practice you should always assume politicians will make a change at some point in the future, and code accordingly.

Your input was invalid (likely)

The legacy class you used was likely rejecting your input as invalid given the DST jump in your JVM’s current default time zone that was implicitly applied since you did not indicate a zone. This strict protocol in parsing for a valid value is not wrong, just one approach in dealing with invalid input.

The ZonedDateTime class uses another approach by default, making an adjustment as it sees fit.

ZonedDateTime

The java.time.ZonedDateTime class knows the time zone’s history of past, present, and future changes to the offset-from-UTC used by the people of a particular region. So that class will adjust automatically. Be sure to read the class documentation so you know and agree to its adjustment protocol.

LocalDateTime

Here is some example code. First we parse your input as a LocalDateTime, because your input lacks any indication of time zone or offset-from-UTC. As such, a LocalDateTime does not represent a moment, is not a point on the timeline. So if a time zone is known to have been intended for that date and time-of-day, we can apply a ZoneId to get a ZonedDateTime.

Here in this example we arbitrarily choose two zones to apply, so you can see the differing results. In the US, March 10 was the day of the DST jump. In much of Europe such as France, the jump is scheduled for later, on the last day of March. So 2 AM is a valid time in France but not in the US.

String input = "20190310022817";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmmss" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

ZoneId zParis = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdtParis = ldt.atZone( zParis ) ;

ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNewYork = ldt.atZone( zNewYork ) ;

Dump to console.

System.out.println( "ldt.toString(): " + ldt ) ;
System.out.println( "zdtParis.toString(): " + zdtParis ) ;
System.out.println( "zdtNewYork.toString(): " + zdtNewYork ) ;

When run. See this code run live at IdeOne.com. Notice the hour on each of these three outputs:

  • 2 AM in the first two
  • 3 AM in the last one

ldt.toString(): 2019-03-10T02:28:17

zdtParis.toString(): 2019-03-10T02:28:17+01:00[Europe/Paris]

zdtNewYork.toString(): 2019-03-10T03:28:17-04:00[America/New_York]

Table of types of date-time class in modern java.time versus legacy.


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.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

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
  • Thanks for going through the use of java.time, which is certainly recommended here. When the question mentions *an invalid date like Feb 30*, I suggest that we want to use `ResolverStyle.STRICT` (or as you know, java,time will just pick Feb 28 instead). – Ole V.V. Mar 20 '19 at 00:13
  • 1
    @OleV.V. I thought of that, but the first sentence of Question contradicts that, suggesting the exception thrown was a surprise. – Basil Bourque Mar 20 '19 at 00:45
  • 1
    @OleV.V. I added a link near the top here to an Answer of mine on a similar Question about `ResolverStyle` enum. I think this covers all the bases now. Thanks! – Basil Bourque Mar 20 '19 at 20:41
0

In Europe, the output is Sun Mar 10 02:28:17 CET 2019, so you should set the time zone first.

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault())
ashraf
  • 54
  • 1
  • 7