IamYipi
IamYipi

Reputation: 13

How to convert timestamp from GMT to Unix epoch

I'm parsing a timestamp which is "2022-01-12T17:17:34.512492+0000", this format is "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'ZZZZ" (ISO8601).

I want to convert it in epoch unix time, I'm using java.text.SimpleDateFormat. I tried two methods but both don't work:

1- First Method

val parsed = "2022-01-12T17:17:34.512492+0000"
val df: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'ZZZZ'")
val date = df.parse(parsed.toString)
val epoch = date.getTime

Error showed:

java.text.ParseException: Unparseable date: "2022-01-12T17:17:34.512492+0000"

2- This second Method shows an output but is incorrect

val parsed = "2022-01-12T17:17:34.512492+0000"
val df: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'+0000'")
val date = df.parse(parsed.toString)
val epoch = date.getTime
println(epoch)

Output:

1642004766492

If you convert this epoch to HUMAN DATE: "Wednesday, 12 January 2022 16:26:06.492"

The hours,minutes and seconds are wrong.

Upvotes: 1

Views: 696

Answers (3)

Alin Gabriel Arhip
Alin Gabriel Arhip

Reputation: 2638

SimpleDateFormat is outdated, as Gael pointed out.

The Time API now supports up to nanoseconds, so microseconds are not an issue here. You should use DateTimeFormatter with ZonedDateTime. Your pattern is slightly wrong. Checking the docs for Offset Z:

Offset Z: This formats the offset based on the number of pattern letters. One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. The output will be '+0000' when the offset is zero. Four letters outputs the full form of localized offset, equivalent to four letters of Offset-O. The output will be the corresponding localized offset text if the offset is zero. Five letters outputs the hour, minute, with optional second if non-zero, with colon. It outputs 'Z' if the offset is zero. Six or more letters throws IllegalArgumentException.

You can also print the time using toInstant to make sure it was parsed correctly:

  import java.time.ZonedDateTime
  import java.time.format.DateTimeFormatter

  val parsed = "2022-01-12T17:17:34.512492+0000"
  val p = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZ"
  val dtf = DateTimeFormatter.ofPattern(p)
  val zdt = ZonedDateTime.parse(parsed, dtf)
  println(zdt.toInstant) // 2022-01-12T17:17:34.512492Z
  println(zdt.toInstant.toEpochMilli) // 1642004254512

Here is a nice article that explains in detail converting an ISO 8601 in Java. The comments at the end are particularly useful, as it shows the difference between the different patterns used.

Upvotes: 2

Pavel D.
Pavel D.

Reputation: 281

The timestamp you have has microseconds precision. Such precision is not supported by SimpleDateFormat. Also, Unix epoch time is usually up to milliseconds precision.

Possible solution here is to explicitly round the microseconds to milliseconds in the string before parsing, then use the yyyy-MM-dd'T'HH:mm:ss.SSSZ format.

String parsed = "2022-01-12T17:17:34.512492+0000";

String upToSeconds = parsed.substring(0, "yyyy-MM-ddTHH:mm:ss".length());
String microseconds = parsed.substring("yyyy-MM-ddTHH:mm:ss.".length(), "yyyy-MM-ddTHH:mm:ss.".length() + "SSSSSS".length());
String timezone = parsed.substring("yyyy-MM-ddTHH:mm:ss.SSSSSS".length());

String roundedMilliseconds = new BigDecimal(microseconds).divide(new BigDecimal("1000"), 0, RoundingMode.HALF_UP).toString();

String reformatted = upToSeconds + "." + roundedMilliseconds + timezone;
System.out.println(reformatted); // 2022-01-12T17:17:34.512+0000

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
long epoch = sdf.parse(reformatted).getTime();

System.out.println(epoch); // 1642007854512
System.out.println(Instant.ofEpochMilli(epoch)); // 2022-01-12T17:17:34.512Z

Upvotes: 0

Alex Delphi
Alex Delphi

Reputation: 21

looks like epoch has data in internal datetime format. and you should convert it to string format like this in java

    public static String dateToString(Date d, String string_format) {
        String result = "";
        if(d != null) {
            result = new SimpleDateFormat(string_format).format(d);
        }
        return result;
    }

Upvotes: 0

Related Questions