-1

I have a java component to format the date that I retrieve. Here is my code:

    Format formatter      = new SimpleDateFormat("yyyyMMdd");
        String s = "2019-04-23 06:57:00.0";
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss.S");
        try
        {
            Date date = simpleDateFormat.parse(s);
            System.out.println("Formatter: "+formatter.format(date));
        }
        catch (ParseException ex)
        {
            System.out.println("Exception "+ex);
        }   

The code works great as long as the String s has the format "2019-04-23 06:57:00.0";

My Question is, how to tweak this code so it will work for below scenarios ex, my s string may have values like


String s = "2019-04-23 06:57:00.0";
or 
String s = "2019-04-23 06:57:00";

Or 
String s = "2019-04-23";

right now it fails if I don't pass the ms.. Thanks!

Stephan Hogenboom
  • 1,543
  • 2
  • 17
  • 29
Anto
  • 3
  • 6
  • Possible duplicate of [How to parse dates in multiple formats using SimpleDateFormat](https://stackoverflow.com/questions/4024544/how-to-parse-dates-in-multiple-formats-using-simpledateformat) – Stephan Hogenboom May 08 '19 at 16:49
  • Use Joda Date API. Same question is already there in stackoverflow and solution as well. I've overcome same challenges long time back. FYI, This functionality is lagging in Java 8 DateTime API. So recommend you to dig in JODA Datetime. – Yanish Pradhananga May 08 '19 at 17:23
  • 2
    FYI, the terribly troublesome date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque May 08 '19 at 18:20
  • 1
    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 `LocalDate`, `LocalDateTime` and `DateTimeFormatter`, all from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. May 09 '19 at 05:42

2 Answers2

4

Different types

String s = "2019-04-23 06:57:00";

String s = "2019-04-23";

These are two different kinds of information. One is a date with time-of-day, the other is simply a date. So you should be parsing each as different types of objects.

LocalDateTime.parse

To comply with the ISO 8601 standard format used by default in the LocalDateTime class, replace the SPACE in the middle with a T. I suggest you educate the publisher of your data about using only ISO 8601 formats when exchanging date-time values as text.

LocalDateTime ldt1 = LocalDateTime.parse( "2019-04-23 06:57:00".replace( " " , "T" ) ) ;

The fractional second parses by default as well.

LocalDateTime ldt2 = LocalDateTime.parse( "2019-04-23 06:57:00.0".replace( " " , "T" ) ) ;

See this code run live at IdeOne.com.

ldt1.toString(): 2019-04-23T06:57

ldt2.toString(): 2019-04-23T06:57

LocalDate.parse

Your date-only input already complies with ISO 8601.

LocalDate ld = LocalDate.parse( "2019-04-23" ) ;

See this code run live at IdeOne.com.

ld.toString(): 2019-04-23

Date with time-of-day

You can strip out the time-of-day from the date.

LocalDate ld = ldt.toLocalDate() ;

And you can add it back in.

LocalTime lt = LocalTime.parse( "06:57:00" ) ;
LocalDateTime ldt = ld.with( lt ) ;

Moment

However, be aware that a LocalDateTime does not represent a moment, is not a point on the timeline. Lacking the context of a time zone or offset-from-UTC, a LocalDateTime cannot hold a moment, as explained in its class JavaDoc.

For a moment, use the ZonedDateTime, OffsetDateTime, or Instant classes. Teach the publisher of your data to include the offset, preferably in UTC.

enter image description here

Avoid legacy date-time classes

The old classes SimpleDateFormat, Date, and Calendar are terrible, riddled with poor design choices, written by people not skilled in date-time handling. These were supplanted years ago by the modern java.time classes defined in JSR 310.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • thank you.. the values are from the database so I think it comply the standards. I will verify this aspect. – Anto May 10 '19 at 13:40
  • @Anto If you are receiving data from a database, you should be extracting date-time objects rather than mere strings. Use `ResultSet::getObject` with a JDBC 4.2 or later driver to get `LocalDate` objects from a `DATE` column and `LocalDateTime` objects from a `TIMESTAMP WITHOUT TIME ZONE` column. This has been covered many times already on Stack Overflow. You should have noted the database as source in your Question. – Basil Bourque May 10 '19 at 13:48
1

In case of you have optional parts in pattern you can use [ and ].

For example

public static Instant toInstant(final String timeStr){
    final DateTimeFormatter formatter = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH[:mm[:ss[ SSSSSSSS]]]")
            .withZone(ZoneId.of("UTC"));
    try {
        return Instant.from(formatter.parse(timeStr));
    }catch (DateTimeException e){
        final DateTimeFormatter formatter2 = DateTimeFormatter
                .ofPattern("yyyy-MM-dd")
                .withZone(ZoneId.of("UTC"));
        return LocalDate.parse(timeStr, formatter2).atStartOfDay().atZone(ZoneId.of("UTC")).toInstant();
    }
}

cover

  • yyyy-MM-dd
  • yyyy-MM-dd HH
  • yyyy-MM-dd HH:mm
  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd HH:mm:ss SSSSSSSS
talex
  • 17,973
  • 3
  • 29
  • 66