0

String has to be converted to type LocalDateTime - "yyyy-MM-dd'T'HH:mm:ss".

Just ignore anything after seconds.

tried this code but errors out for anything that comes after seconds.

String testDate = "2019-09-17T23:38:47";



LocalDateTime lDate = null;
            if (!StringUtils.isEmpty(testDate) && !"".equals(testDate)) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
                try {
                    sqlDate = LocalDateTime.parse(testDate, formatter);
                    log.info("Converted SQL date=" + lDate );
                } catch (Exception ex) {
                    log.error("Error in parsing lDate " +ex);
                }
            }
Geek
  • 3,187
  • 15
  • 70
  • 115

1 Answers1

2

Try this: (+ exception handling)

String testDate = "2019-09-17T23:38:47.342";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
java.util.Date date = format.parse(testDate);
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(localDateTime);
System.out.println(localDateTime.getNano());

Output:

2019-09-17T23:38:47
0

As you can see, the fractional seconds are eliminated.

Edit:
Here's a solution with more recent date-time classes:

DateTimeFormatter format = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
    .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
    .toFormatter();
LocalDateTime date1 = LocalDateTime.parse("2019-09-17T23:38:47", format).withNano(0);
LocalDateTime date2 = LocalDateTime.parse("2019-09-17T23:38:47.342", format).withNano(0);
System.out.println(date1);
System.out.println(date2);

Output:

2019-09-17T23:38:47
2019-09-17T23:38:47

Edit 2:
I've constructed an example for how you might deal with different types of inputs using regular expressions and format strings:

InputDatePattern.java

public enum InputDatePattern
{
    WITH_TIMESTAMP("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{0,9})?", Optional.of("yyyy-MM-dd'T'HH:mm:ss")), 
    WITHOUT_TIMESTAMP("\\d{4}-\\d{2}-\\d{2}", Optional.of("yyyy-MM-dd")),
    TIMESTAMP_ONLY("\\d{2}:\\d{2}:\\d{2}(\\.\\d{0,9})?", Optional.of("HH:mm:ss")),
    UNKNOWN(".*", Optional.empty()); // must come last, since elements are matched in order
    private final Pattern pattern;
    private final Optional<DateTimeFormatter> formatter;

    private static final LocalDate DEFAULT_DATE = LocalDate.EPOCH;
    private static final LocalTime DEFAULT_TIME = LocalTime.MIDNIGHT;
    private static final Logger log = Logger.getLogger(Logger.class.getName());

    private InputDatePattern(String regex, Optional<String> format)
    {
        pattern = Pattern.compile(regex);
        var formatter = Optional.of(new DateTimeFormatterBuilder());
        formatter.ifPresent(f -> format.ifPresent(f::appendPattern));
        formatter.ifPresent(f -> f.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true));
        this.formatter = formatter.map(DateTimeFormatterBuilder::toFormatter);
    }

    public boolean matches(String type)
    {
        return pattern.matcher(type).matches();
    }

    public Optional<LocalDateTime> toLocalDateTime(String dateString)
    {
        try
        {
            switch(this)
            {
            case WITH_TIMESTAMP:
                return formatter.map(f -> LocalDateTime.parse(dateString, f).withNano(0));
            case WITHOUT_TIMESTAMP:
                return toLocalDate(dateString).map(date -> date.atTime(DEFAULT_TIME).withNano(0));
            case TIMESTAMP_ONLY:
                return toLocalTime(dateString).map(date -> date.atDate(DEFAULT_DATE).withNano(0));
            case UNKNOWN:
                return Optional.empty();
            default:
                throw new IllegalStateException("Attempting conversion with unknown InputDatePattern!");
            }
        }
        catch(DateTimeParseException e)
        {
            log.info(e.getMessage());
            return Optional.empty();
        }
    }

    public Optional<LocalDate> toLocalDate(String dateString)
    {
        try
        {
            switch(this)
            {
            case WITH_TIMESTAMP:
            case WITHOUT_TIMESTAMP:
                return formatter.map(f -> LocalDate.parse(dateString, f));
            case TIMESTAMP_ONLY:
            case UNKNOWN:
                return Optional.empty();
            default:
                throw new IllegalStateException("Attempting conversion with unknown InputDatePattern!");
            }
        }
        catch(DateTimeParseException e)
        {
            log.info(e.getMessage());
            return Optional.empty();
        }
    }

    public Optional<LocalTime> toLocalTime(String dateString)
    {
        try
        {
            switch(this)
            {
            case WITH_TIMESTAMP:
            case TIMESTAMP_ONLY:
                return formatter.map(f -> LocalTime.parse(dateString, f));
            case WITHOUT_TIMESTAMP:
            case UNKNOWN:
                return Optional.empty();
            default:
                throw new IllegalStateException("Attempting conversion with unknown InputDatePattern!");
            }
        }
        catch(DateTimeParseException e)
        {
            log.info(e.getMessage());
            return Optional.empty();
        }
    }

    public static InputDatePattern forDateString(String dateString)
    {
        for(InputDatePattern pattern : InputDatePattern.values())
        {
            if(pattern.matches(dateString))
                return pattern;
        }
        return InputDatePattern.UNKNOWN;
    }
}

Demo.java

public class Demo
{
    public static void main(String[] args)
    {
        String[] trying = {"2019-09-17T23:38:00", "2019-09-17T23:38:00.123",
                "2019-09-17", "bad input", "09:12:13.45"};
        for(String str : trying)
        {
            InputDatePattern pattern = InputDatePattern.forDateString(str);
            System.out.format("Input pattern type for %s is %s%n", str, pattern);
            Optional<LocalDateTime> localDateTime = pattern.toLocalDateTime(str);
            if(localDateTime.isPresent())
            {
                System.out.println("The corresponding LocalDateTime is: "+localDateTime.get());
            }
            else
            {
                System.out.format("Unknown type of LocalDateTime! Bad input=\"%s\"%n",str);
            }
        }
    }
}

Output:

Input pattern type for 2019-09-17T23:38:00 is WITH_TIMESTAMP
The corresponding LocalDateTime is: 2019-09-17T23:38
Input pattern type for 2019-09-17T23:38:00.123 is WITH_TIMESTAMP
The corresponding LocalDateTime is: 2019-09-17T23:38
Input pattern type for 2019-09-17 is WITHOUT_TIMESTAMP
The corresponding LocalDateTime is: 2019-09-17T00:00
Input pattern type for bad input is UNKNOWN
Unknown type of LocalDateTime! Bad input="bad input"
Input pattern type for 09:12:13.45 is TIMESTAMP_ONLY
The corresponding LocalDateTime is: 1970-01-01T09:12:13
Avi
  • 2,611
  • 1
  • 14
  • 26
  • @RealSkeptic This solution eliminates the fractional seconds. – Avi Sep 24 '19 at 16:49
  • The OP's problem is that they get a date string that *includes* fractional second and need to parse it. Your example does not include those. – RealSkeptic Sep 24 '19 at 16:50
  • @JNPW Changed the `var`s to class names :) – Avi Sep 24 '19 at 17:15
  • @Avi with this working i am thinking what if i get only date with no time stamp only yyyy-MM-dd. Can i still consume this date without erroring out? – Geek Sep 24 '19 at 17:17
  • @JNPW If your input doesn't match the expected pattern, you're going to run into issues. I'd suggest checking for the type of match preemptively, and then dispatching the string to an appropriate DateTimeFormatter as decided by which pattern it matches. – Avi Sep 24 '19 at 17:19
  • @Avi The string can be anything just worst case assuming yyyy-MM-dd. – Geek Sep 24 '19 at 17:21
  • @JNPW I'll make an example explaining what I'm talking about, be patient :) – Avi Sep 24 '19 at 17:24
  • @JNPW I'm done :) – Avi Sep 24 '19 at 19:08