Search code examples
javadate-formatdate-formattinglocaldatedateformatter

convert String to DateTime java


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);
                }
            }

Solution

  • 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