Olahzzz
Olahzzz

Reputation: 571

How to convert string with this format to Java 8 time and convert to long milliseconds

I have a MapperUtility class that needs to map a string from a web service that sends a string time "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)"

Now, I am converting it to LocalDateTime with this code:

String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ssZ");
dtf.withZone(ZoneId.of("UTC"));
LocalDateTime convertedDate = LocalDateTime.parse(time, dtf);

But I am having an exception starting the GMT+0000 (UTC). It works when I removed the characters beyond the GMT. After converting them to Date Time, I need to convert them to long milliseconds. Please advise. Thanks.

Upvotes: 2

Views: 2012

Answers (3)

Anonymous
Anonymous

Reputation: 86323

    String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ss 'GMT'xx (zzz)", Locale.ENGLISH);
    ZonedDateTime zdt = ZonedDateTime.parse(time, dtf);
    OffsetDateTime odt = OffsetDateTime.parse(time, dtf);
    boolean offsetAgrees = zdt.getOffset().equals(odt.getOffset());
    if (offsetAgrees) {
        long millisecondsSinceEpoch = odt.toInstant().toEpochMilli();
        System.out.println("Milliseoncds: " + millisecondsSinceEpoch);
    } else {
        System.out.println("Offset " + odt.getOffset() + " does not agree with time zone " + zdt.getZone());
    }

Output:

Milliseoncds: 1385122333000

I am parsing GMT as a literal, +0000 as an offset and UTC as a time zone abbreviation. For the offset we could have used xx or ZZZ. Since Fri and Nov are in English, we need to specify an English speaking locale.

I have added a little complication compared to your code because we want to validate that the offset and the time zone agree. OffsetDateTime.parse uses the offest (+0000) directly whereas ZonedDateTime.parse derives the offset from the time zone ( UTC). My check is very bare-bones and may be extended to accept two possible offsets in the transition from summer time (DST) and multiple time zones sharing the same abbreviation.

PS Don’t use LocalDateTime. This type can neither hold an offset nor time zone, so you can no longer attach your date and time to a specific point on the time line, which you need to do to obtain milliseconds since the epoch.

Upvotes: 0

Alex Salauyou
Alex Salauyou

Reputation: 14348

You may build such pattern using DateTimeFormatterBuilder:

static final DateTimeFormatter DF = new DateTimeFormatterBuilder()
    .append(DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ss"))
    .appendLiteral(" GMT")
    .appendOffset("+HHmm", "+0000")
    .optionalStart()
    .appendLiteral(" (")
    .appendZoneId()
    .appendLiteral(')')
    .optionalEnd()
    .toFormatter()
    .withLocale(Locale.US);

Then, just:

String date = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
long ms = OffsetDateTime.parse(date, DF).toInstant().toEpochMilli();  // 1385122333000

Upvotes: 1

Mark Jeronimus
Mark Jeronimus

Reputation: 9541

An inefficient way to make the parser accept your string verbatim is:

String[] timezones = {"UTC", "BST", "CET", "PST", ...};

StringBuilder sb = new StringBuilder(timezones.length * 8 + 38);
sb.append("E MMM dd yyyy HH:mm:ss' GMT'Z' ('");
for(String timezone : timezones)
    sb.append("['").append(timezone).append("']");
sb.append("')'");

DateTimeFormatter dtf = DateTimeFormatter.ofPattern(sb.toString());
String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
ZonedDateTime convertedDate = ZonedDateTime.parse(time, dtf);
System.out.println(convertedDate);

I changed to ZonedDateTime too because otherwise it discards the timezone and always returns 12:12:13 regardless of what's after the GMT+.

But it gets unwieldy pretty quick because of the inexhaustible list of possible time zone abbreviations.

A better way is to preprocess the string:

String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";

String preprocessed = time.replaceAll("(.*) GMT([+-][0-9]{4}).*", "$1$2");
System.out.println(preprocessed);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ssZ");
ZonedDateTime convertedDate = ZonedDateTime.parse(preprocessed, dtf);
System.out.println(convertedDate);

Then the conversion to milliseconds is a bit tricky to find in the extensive java.time API but eventually it turns out to be as simple as:

convertedDate.toInstant().toEpochMilli()

Upvotes: 1

Related Questions