-3

I want to convert multiple string date format into a timestamp

For Example, I have the following string of dates like below

String date1 = "2020-01-01 12:23:30.345"
String date2 = "2020-01-01 12:23:30"
String date3 = "2020-01-01 12:23"
String date4 = "2020-01-01 12"

I want to convert all the above strings format into timestamp like,

For date1, Timestamp should be 2020-01-01 12:23:30.345 UTC
For date2, Timestamp should be 2020-01-01 12:23:30.000 UTC
For date3, Timestamp should be 2020-01-01 12:23:00.000 UTC
For date4, Timestamp should be 2020-01-01 12:00:00.000 UTC

Could you please help me with this? Any info will be really helpful. I can't define single string formatted for parser since the string format is unpredictable in my scenario.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
saravana kumar
  • 255
  • 1
  • 3
  • 10
  • Also Timestamp now is legacy, I recommend to about learn [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) library – Youcef LAIDANI Dec 14 '20 at 14:33

2 Answers2

4

You can use two formatter one to convert String to LocalDateTime and the other to convert from LocalDateTime to the expected String :

String[] dates = {date1, date2, date3, date4};
DateTimeFormatter formatterIn = DateTimeFormatter.ofPattern("yyyy-MM-dd HH[:mm][:ss][.SSS]");
DateTimeFormatter formatterOut = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

for (String date : dates) {
    LocalDateTime ldtIn = LocalDateTime.parse(date, formatterIn);
    String ldtOut = ldtIn.format(formatterOut);
    System.out.println(ldtOut);
}

Outputs

2020-01-01 12:23:30.345
2020-01-01 12:23:30.000
2020-01-01 12:23:00.000
2020-01-01 12:00:00.000
Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
  • 2
    It's safer to use `uuuu` instead of `yyyy`. Please check [this discussion](https://stackoverflow.com/questions/41177442/uuuu-versus-yyyy-in-datetimeformatter-formatting-pattern-codes-in-java) as a reference. – Arvind Kumar Avinash Dec 14 '20 at 14:44
4

You can use the optional pattern (inside square bracket) for the missing parts. You can also use DateTimeFormatterBuilder#parseDefaulting to default the missing parts of time to 0 or any other value.

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtfForFormating = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS", Locale.ENGLISH);

        // Tests
        System.out.println(getLocalDateTime("2020-01-01 12:23:30.345"));
        System.out.println(getLocalDateTime("2020-01-01 12:23:30.345").format(dtfForFormating));
        
        System.out.println(getLocalDateTime("2020-01-01 12:23:30"));
        System.out.println(getLocalDateTime("2020-01-01 12:23:30").format(dtfForFormating));
        
        System.out.println(getLocalDateTime("2020-01-01 12:23"));
        System.out.println(getLocalDateTime("2020-01-01 12:23").format(dtfForFormating));
        
        System.out.println(getLocalDateTime("2020-01-01 12"));
        System.out.println(getLocalDateTime("2020-01-01 12").format(dtfForFormating));
    }

    static LocalDateTime getLocalDateTime(String text) {
        DateTimeFormatter multiFormatter = new DateTimeFormatterBuilder()
                                            .appendPattern("uuuu-MM-dd HH[:mm][:ss][.SSS]")
                                            .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
                                            .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                                            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)                                         
                                            .toFormatter(Locale.ENGLISH);

        return LocalDateTime.parse(text, multiFormatter);
    }
}

Output:

2020-01-01T12:23:30.345
2020-01-01 12:23:30.345
2020-01-01T12:23:30
2020-01-01 12:23:30.000
2020-01-01T12:23
2020-01-01 12:23:00.000
2020-01-01T12:00
2020-01-01 12:00:00.000

Update

This is an update based on the OP's request to have timezone with the date-time.

LocalDateTime does not have timezone information. In order to have the timezone information, you need to convert it into ZonedDateTime.

Demo:

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtfForFormating = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS z", Locale.ENGLISH);

        // Tests
        System.out.println(getZonedDateTime("2020-01-01 12:23:30.345"));
        System.out.println(getZonedDateTime("2020-01-01 12:23:30.345").format(dtfForFormating));

        System.out.println(getZonedDateTime("2020-01-01 12:23:30"));
        System.out.println(getZonedDateTime("2020-01-01 12:23:30").format(dtfForFormating));

        System.out.println(getZonedDateTime("2020-01-01 12:23"));
        System.out.println(getZonedDateTime("2020-01-01 12:23").format(dtfForFormating));

        System.out.println(getZonedDateTime("2020-01-01 12"));
        System.out.println(getZonedDateTime("2020-01-01 12").format(dtfForFormating));
    }

    static ZonedDateTime getZonedDateTime(String text) {
        DateTimeFormatter multiFormatter = new DateTimeFormatterBuilder()
                                            .appendPattern("uuuu-MM-dd HH[:mm][:ss][.SSS]")
                                            .parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
                                            .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                                            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                                            .toFormatter(Locale.ENGLISH);

        return LocalDateTime.parse(text, multiFormatter).atZone(ZoneId.of("Etc/UTC"));
    }
}

Output:

2020-01-01T12:23:30.345Z[Etc/UTC]
2020-01-01 12:23:30.345 UTC
2020-01-01T12:23:30Z[Etc/UTC]
2020-01-01 12:23:30.000 UTC
2020-01-01T12:23Z[Etc/UTC]
2020-01-01 12:23:00.000 UTC
2020-01-01T12:00Z[Etc/UTC]
2020-01-01 12:00:00.000 UTC
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • Hi Arvind, Thanks for the solution, It's worked fine. One more question, Among with timestamp how can be add timezone as an optional pattern. For example: If my input string is "2020-01-01 12:30" I should get my output string as "2020-01-01 12:30:00.000 UTC" – saravana kumar Dec 14 '20 at 15:35
  • Hi Arvind, I guess my question is closed. Could you please paste an updated one in this chat? I tried to re-open it, But I'm getting some error. – saravana kumar Dec 14 '20 at 15:49
  • @saravanakumar - You are most welcome. Wish you success! I've added it as an update. – Arvind Kumar Avinash Dec 14 '20 at 16:06
  • Fine answer. (1) I’d nest the brackets since we only allow seconds when minutes are there and only millis when there are seconds. (2) Wihle the calls to `parseDefaulting()` may help understanidng, we can also fo without them if we want (as long as we want to default to 0). So just: `DateTimeFormatter multiFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH[:mm[:ss[.SSS]]]", Locale.ENGLISH);`. – Ole V.V. Dec 14 '20 at 18:49