date and time show parse error at specific index

1.3k views Asked by At

I am getting date and time from JSON API URL which format is like this

    '2021-03-05 09:18:07' which is in String form.

but when I want to convert it in milliseconds it gives me an error of index 10. I don't know why this issue is coming I check other Stackoverflow answer but did not successed

  DateTimeFormatter formatter ;
                                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                                    formatter = DateTimeFormatter.ofPattern(
                                            "yyyy-MM-dd'T'HH:mm:ss", Locale.ROOT);
                                    String dates = object.getString("created_at");
                                   long  timeInMilliseconds = OffsetDateTime.parse(dates, formatter)
                                            .toInstant()
                                            .toEpochMilli();
                                    System.out.println("Date in milli :: USING ThreeTenABP >>> " + 
                                   timeInMilliseconds);

                                }
                                String text = TimeAgo.using(timeInMilliseconds);
                                FeedModel.setDateSnap(text);

and here is error

     java.time.format.DateTimeParseException: Text '2021-03-05 09:18:07' could not be parsed: Unable 
     to obtain OffsetDateTime from TemporalAccessor: {},ISO resolved to 2021-03-05T09:18:07 of type 
     java.time.format.Parsed
    at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:396)
    at com.example.wasigram.MainActivity$1.onResponse(MainActivity.java:91)
    at com.androidnetworking.common.ANRequest.deliverSuccessResponse(ANRequest.java:729)
    at com.androidnetworking.common.ANRequest.access$6500(ANRequest.java:80)
    at com.androidnetworking.common.ANRequest$6.run(ANRequest.java:709)
    at android.os.Handler.handleCallback(Handler.java:888)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:213)
    at android.app.ActivityThread.main(ActivityThread.java:8178)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
 Caused by: java.time.DateTimeException: Unable to obtain OffsetDateTime from TemporalAccessor: {},ISO resolved to 2021-03-05T09:18:07 of type java.time.format.Parsed
    
2

There are 2 answers

0
Arvind Kumar Avinash On BEST ANSWER

Using Java SE 8 API:

You can use DateTimeFormatter#withZone to get a formatter with the specified zone.

Also, use the correct format, yyyy-MM-dd HH:mm:ss which does not have 'T' which you have put in your pattern by mistake. In fact, I prefer using u to y as explained in this answer.

Demo:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2021-03-05 09:18:07";
        
        DateTimeFormatter formatter = DateTimeFormatter
                                        .ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH)
                                        .withZone(ZoneOffset.UTC);
        
        long millis = OffsetDateTime
                        .parse(strDateTime, formatter)
                        .toInstant()
                        .toEpochMilli();
        
        System.out.println(millis);
    }
}

Output:

1614935887000

Learn more about the modern date-time API from Trail: Date Time.

Using ThreeTen-Backport API:

import java.util.Locale;

import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2021-03-05 09:18:07";
        
        DateTimeFormatter formatter = DateTimeFormatter
                                        .ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
        
        long millis = LocalDateTime
                        .parse(strDateTime, formatter)
                        .toInstant(ZoneOffset.UTC)
                        .toEpochMilli();
        
        System.out.println(millis);
    }
}

Output:

1614935887000
4
Anonymous On

You’ve got two issues:

  1. Your format pattern string does not exactly match your string from JSON.
  2. You cannot naïvely parse a stirng that doesn’t contain a UTC offset into an OffsetDateTime.

The format pattern string

Index 10 in your string 2021-03-05 09:18:07 is where the space after the day of month is. So let’s look at your format pattern to see what is expected to come after the day of month. Your format pattern string is yyyy-MM-dd'T'HH:mm:ss, and after the day of month comes 'T', which means a literal T, that is, the T is not a pattern letter. Your exception comes because a T and a space are not equal.

A tip for parsing problems: When you cannot see what’s wrong in parsing, try formatting first.

    String dates = "2021-03-05 09:18:07";
    DateTimeFormatter formatter 
            = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss", Locale.ROOT);
    
    OffsetDateTime expectedResult
            = OffsetDateTime.of(2021, 3, 5, 9, 18, 7, 0, ZoneOffset.ofHours(1));
    
    System.out.println("Parsing:   " + dates);
    System.out.println("Formatted: " + expectedResult.format(formatter));

Output is:

Parsing:   2021-03-05 09:18:07
Formatted: 2021-03-05T09:18:07

I hope that it’s now easier to see the difference between the space in your string and the T in the string that the formatter expects.

You may have figured the solution out already: in the format pattern string put a space instead of 'T' (if you like, you can put the space in single quotes, but it’s not necessary).

Parsing into an OffsetDateTime

This fix still fails:

    // Put a space in the format pattern string
    DateTimeFormatter formatter 
            = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
    
    OffsetDateTime odt = OffsetDateTime.parse(dates, formatter);

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-03-05 09:18:07' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {},ISO resolved to 2021-03-05T09:18:07 of type java.time.format.Parsed

Funnily this is also the exception in the stack trace in your question.

An OffsetDateTime must contain an offset from UTC, and Java has got no place to get it from. Do you know which time zone is assumed by the API that you got the string from? If so, use it. My suggestion is:

    ZoneId zoneAssumedByApi = ZoneId.of("Antarctica/Troll");
    long  timeInMilliseconds = LocalDateTime.parse(dates, formatter)
            .atZone(zoneAssumedByApi)
            .toInstant()
            .toEpochMilli();
    System.out.println("Date in milli :: USING ThreeTenABP >>> "
            + timeInMilliseconds);

Date in milli :: USING ThreeTenABP >>> 1614935887000