简体   繁体   中英

How to parse UTC timestamp of format yyyy-MM-ddTHH:mm:ss.SSS+ZZZZ

I have timestamp as 2020-12-03T05:35:59.398+0000 in String format being recieved in a streaming batch.

I want only 2020-12-03 05:35:59 as java.sql.Timestamp instance in order to be able to compare it with other Timestamp instance.

Getting following error with Timestamp.valueOf() function:

Exception in thread "main" java.time.format.DateTimeParseException : Text '2020-12-03T05:35:59.398+0000' could not be parsed at index 23

I tried the answer given here , and conversion did happen but the time was changed to 2020-12-03 11:05:59

I have tried changing between the formats given here but still no solution.

Is there even a format for timestamp with wierd + in between 398+0000 ?

java.time

I recommend that you use java.time, the modern Java date and time API, for your date and time work.

    DateTimeFormatter isoFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
    DateTimeFormatter sqlTimestampFormatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral(' ')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .toFormatter();
    
    String aTimestampString = "2020-12-03T05:35:59.398+0000";
    String anotherTimestampString = "2020-12-04 06:43:58.556385";
    
    Instant anInstant = isoFormatter.parse(aTimestampString, Instant::from);
    Instant anotherInstant = LocalDateTime.parse(anotherTimestampString, sqlTimestampFormatter)
            .atOffset(ZoneOffset.UTC)
            .toInstant();
    
    if (anInstant.isBefore(anotherInstant)) {
        System.out.println(aTimestampString + " is earlier");
    } else {
        System.out.println(anotherTimestampString + " is earlier");
    }

Output from this example is:

2020-12-03T05:35:59.398+0000 is earlier

The +0000 in the former string above is an offset from UTC — an offset of 00 hours 00 minutes. Since it is zero, we know that the time is in UTC. I don't know the time zone or UTC offset of the other string. You need to know, or you will get incorrect results. In the code above I have assumed that the other string is in UTC too.

Don't use Timestamp

I tried the answer given here, and conversion did happen but the time was changed to 2020-12-03 11:05:59

This is how confusing the Timestamp class is. You got the correct timestamp value. What happens when you print the Timestamp object, is that you are (implicitly or explicitly) calling its toString method. Timestamp.toString() confusingly uses the default time zone of your JVM for rendering the string. So if your timestamp is equal to 2020-12-03T05:35:59.398 UTC and your time zone is, say, Asia/Kolkata, then time is converted to Asia/Kolkata time zone and the string 2020-12-03 11:05:59 is returned and printed.

You have nothing good to use the old-fashioned java.sql.Timestamp class for. It was originally meant for transferring timestamp values with and without time zone to and from SQL databases. Since JDBC 4.2 we prefer OffsetDateTime , Instant and LocalDateTime for that purpose. So just forget about the Timestamp class.

Link

Oracle tutorial: Date Time explaining how to use java.time.

Is there even a format for timestamp with wierd + in between 398+0000?

The 398 part is fraction-of-second (millisecond) while the +0000 part is the zone offset part.

You can parse 2020-12-03T05:35:59.398+0000 into an OffsetDateTime using the format pattern, uuuu-MM-dd'T'HH:mm:ss.SSSX .

Demo:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        String text = "2020-12-03T05:35:59.398+0000";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
        OffsetDateTime odt = OffsetDateTime.parse(text, formatter);
        System.out.println(odt);
    }
}

Output:

2020-12-03T05:35:59.398Z

Check the DateTimeFormatter documentation page to learn more about the letters used for formatting.

You can use isBefore and isAfter functions of OffsetDateTime to compare its two instances.

Demo:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        String text = "2020-12-03T05:35:59.398+0000";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
        OffsetDateTime odt = OffsetDateTime.parse(text, formatter);
        OffsetDateTime odtNow = OffsetDateTime.now();
        System.out.println(odtNow.isBefore(odt));
        System.out.println(odtNow.isAfter(odt));
    }
}

Output:

false
true

Learn more about the modern date-time API at Trail: Date Time . If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project .

The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API . Since java.sql.Timestamp extends java.util.Date , it is recommended to stop using that as well. However, for any reason, if you still want to use conversion between the modern and the legacy date-time API, use Instant as the bridge.

import java.sql.Timestamp;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        String text = "2020-12-03T05:35:59.398+0000";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
        OffsetDateTime odt = OffsetDateTime.parse(text, formatter);
        Instant instant = odt.toInstant();
        Timestamp timestamp = new Timestamp(instant.toEpochMilli());
        System.out.println(timestamp);
    }
}

Output:

2020-12-03 05:35:59.398

You can use a custom DateFormatter for non-standard formats. Here is a working example for your use case.

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;

import static java.time.temporal.ChronoField.*;

public class Main {

    private static final DateTimeFormatter INPUT_NON_STANDARD_FORMAT;

    static {
        INPUT_NON_STANDARD_FORMAT =
                new DateTimeFormatterBuilder()
                        .parseCaseInsensitive()
                        .append(DateTimeFormatter.ISO_LOCAL_DATE)
                        .appendLiteral('T')
                        .appendValue(HOUR_OF_DAY, 2)
                        .appendLiteral(':')
                        .appendValue(MINUTE_OF_HOUR, 2)
                        .optionalStart()
                        .appendLiteral(':')
                        .appendValue(SECOND_OF_MINUTE, 2)
                        .optionalStart()
                        .appendLiteral('.')
                        .appendValue(MILLI_OF_SECOND, 3)
                        .appendLiteral("+0000")
                        .toFormatter();
    }

    public static void main(String[] args) {
        String timestamp = "2020-12-03T05:35:59.398+0000";
        final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse(timestamp, INPUT_NON_STANDARD_FORMAT);
        System.out.println(localDateTime.format(dateTimeFormatter));
    }
}

Output

2020-12-03 05:35:59

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM