Parsing a timestamp with Timezone

Asked

Viewed 724 times

2

I was making a little code to implement a treatment case in a friend’s application module and got stuck with a problem.

This is a unitary test. To put in the application module I would have to make some adjustments when entering in his native code, but basically I’m getting one String of a database in a format similar to String given below:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
  public static void main(String args[]) throws ParseException {
    String value = "2018-4-25 0.0.0.0 -3:00";
    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yy HH:mm:ss");

    if (value.charAt(6) == '-') {
        SimpleDateFormat myformat = new SimpleDateFormat("yyyy-M-dd H.m.s.S X");
        Date d1 = myformat.parse(value);
        String result = sdf.format(d1);
        result = result + ", " + "000000000 " + "-03:00";
        System.out.println(result);

    } else {
        SimpleDateFormat myformat = new SimpleDateFormat("yyyy-MM-dd H.m.s.S X");
        Date d1 = myformat.parse(value);
        String result = sdf.format(d1);
        result = result + ", " + "000000000 " + "-03:00";
        System.out.println(result);
      }
  }
}

But the message I get is:

"C:\Program Files\Java\jdk-10.0.1\bin\java.exe" "-javaagent:C:\Program Files (x86)\IntelliJ IDEA\lib\idea_rt.jar=63052:C:\Program Files (x86)\IntelliJ IDEA\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\...\IdeaProjects\untitled\out\production\untitled Main

Exception in thread "main" java.text.ParseException: Unparseable date: "2018-4-25 0.0.0.0 -3:00"
    at java.base/java.text.DateFormat.parse(DateFormat.java:395)
    at Main.main(Main.java:23)

Process finished with exit code 1

Could someone help me?

  • Our language is the Português, translate your question.

  • Sorry, I hadn’t noticed q is in en Anyway, it’s a code that I get a string from a database and need to convert to Date. However, the parse is not going well. That’s what I don’t understand

  • 1

    Translate your question first, otherwise it will be closed.

  • Ready! Thank you!

2 answers

3

Different form of the format X:

Letter  Component     Presentation         Examples
X       Time zone     ISO 8601 time zone   -08; -0800; -08:00

and more

ISO8601TimeZone:
         OneLetterISO8601TimeZone
         TwoLetterISO8601TimeZone
         ThreeLetterISO8601TimeZone
 OneLetterISO8601TimeZone:
         Sign TwoDigitHours
          Z
 TwoLetterISO8601TimeZone:
         Sign TwoDigitHours Minutes
          Z
 ThreeLetterISO8601TimeZone:
         Sign TwoDigitHours  : Minutes
          Z

i.e., the format for the time zone, using the format X, requires double digits for the time. If you try to interpret the text "2018-4-25 0.0.0.0 -03:00" should work. Other option: add "GMT" before the time zone - "2018-4-25 0.0.0.0 GMT-3:00" - and use the format z or Z.

Your code is also a little strange - it is not necessary to test if the seventh letter (Dice 6) is -. For example for interpretation with the format y, the class SimpleDateFormat only differentiates between the abbreviated format ("y" or "yy") and the complete with more than two repetitions of the y. Similar to the interpretation of the month...

That response was based on official documentation

1

As stated in carlos' answer, the class SimpleDateFormat supports only offsets with 2 digits at the time (something like -03:00).

One way around this problem is to break the String in 2 parts: one with the date and time, and the other with the offset, and use this value to set Timezone SimpleDateFormat:

String value = "2018-4-25 0.0.0.0 -3:00";
// separar data e hora (2018-4-25 0.0.0.0) do offset (-3:00)
Matcher matcher = Pattern.compile("^(.*) ([\\+\\-]\\d{1,2}:\\d\\d)$").matcher(value);
if (matcher.matches()) {
    String datetime = matcher.group(1);
    String offset = matcher.group(2);

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-dd H.m.s.S");
    // felizmente, a classe TimeZone aceita offsets com um dígito na hora
    sdf.setTimeZone(TimeZone.getTimeZone("GMT" + offset));

    Date date = sdf.parse(datetime);
}

Depending on the version of Java you use, you can also use the API java.time (from Java 8). You use this API to parse and then convert to java.util.Date.

In Java 6 and 7, it is also possible to use these classes through Threeten Backport - the classes are practically the same, the only differences are that they stay in the package org.threeten.bp (instead of java.time) and the conversion to Date is slightly different from Java 8 (I will explain below).

Anyway, Java 8 also has this problem of not accepting offsets with only one digit in the hours. This was only fixed in Java 9.

Code in Java 8, using java.time (or Java 6 and 7 using Threeten Backport) is below. Note that the date/time and the offset are treated separately, and then united to create a java.time.OffsetDateTime, which is then converted to Date.

To make the Parsing I use a java.time.format.DateTimeFormatter for the date/time and another for the offset. The result of the date and time is placed in a java.time.LocalDateTime (a class that has exactly that: only the date and time), and the offset is placed in a java.time.ZoneOffset (a class representing a offset - in the case, the -3:00).

String value = "2018-4-25 0.0.0.0 -3:00";
Matcher matcher = Pattern.compile("^(.*) ([\\+\\-]\\d{1,2}:\\d\\d)$").matcher(value);
if (matcher.matches()) {
    String datetime = matcher.group(1);
    String offset = matcher.group(2);
    DateTimeFormatter datetimeParser = DateTimeFormatter.ofPattern("uuuu-M-dd H.m.s.S");
    DateTimeFormatter offsetParser = DateTimeFormatter.ofPattern("O");

    LocalDateTime dt = LocalDateTime.parse(datetime, datetimeParser);
    ZoneOffset zOffset = ZoneOffset.from(offsetParser.parse("GMT" + offset));
    OffsetDateTime odt = dt.atOffset(zOffset);

    // converte para java.util.Date
    // Java 8
    Date date = Date.from(odt.toInstant());

    // Java 6 e 7 (ThreeTen Backport)
    Date date = DateTimeUtils.toDate(odt.toInstant());
}

From Java 9, it is possible to do the Parsing at once:

String value = "2018-4-25 0.0.0.0 -3:00";
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // data e hora
    .appendPattern("uuuu-M-dd H.m.s.S ")
    // offset com um dígito nas horas
    .appendOffset("+H:MM", "+0:00")
    // criar formatter
    .toFormatter();
OffsetDateTime odt = OffsetDateTime.parse(value, fmt);

Date date = Date.from(odt.toInstant());

Browser other questions tagged

You are not signed in. Login or sign up in order to post.