Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parsing ISO8601 DateTime with time zones formatted as "+0000" #139

Closed
nathanscb opened this issue Aug 25, 2021 · 17 comments
Closed

Parsing ISO8601 DateTime with time zones formatted as "+0000" #139

nathanscb opened this issue Aug 25, 2021 · 17 comments
Labels
formatters Related to parsing and formatting

Comments

@nathanscb
Copy link

Parsing a string as an Instant like 2021-08-22T03:32:10+0000 fails due to fixOffsetRepresentation adding :00 to the end of the string.

The underlying Java Time library is able to handle this fine.

@nathanscb nathanscb changed the title Parsing ISO8601 DateTime with time zones formatted as +"0000" Parsing ISO8601 DateTime with time zones formatted as "+0000" Aug 25, 2021
@ilya-g
Copy link
Member

ilya-g commented Aug 27, 2021

In JDK 8, which this library targets to on JVM, java.time does not support parsing such format by default: neither Instant, nor OffsetDateTime can do it. Perhaps it was supported in more recent versions of JDK, in that case we could think how to retrofit this capability to JDK 8 implementation.

@ilya-g ilya-g added the enhancement New feature or request label Aug 27, 2021
@dkhalanskyjb
Copy link
Collaborator

@nathanscb, could you please provide a complete snippet where 2021-08-22T03:32:10+0000 is successfully parsed, along with the JVM version? I just checked this on JRE 11 and JRE 16 (OpenJDK), and OffsetDateTime.parse("2021-08-22T03:32:10+0000") fails with Text '2021-08-22T03:32:10+0000' could not be parsed, unparsed text found at index 22, while Instant.parse("2021-08-22T03:32:10+0000") fails with Text '2021-08-22T03:32:10+0000' could not be parsed at index 19. The documentation seems to agree with these results: https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/time/OffsetDateTime.html#parse(java.lang.CharSequence)

@dkhalanskyjb dkhalanskyjb added the waiting for clarification Additional information is needed from the user label Sep 2, 2021
@merlin-zaraza
Copy link

Hi. This line of code documentation states that Instant can parse such kind of format Instant.kt

@dkhalanskyjb
Copy link
Collaborator

@merlin-zaraza , but the link you provided is not to our repository but to something else. In our repository, there's no such line: https://github.com/Kotlin/kotlinx-datetime/blob/master/core/common/src/Instant.kt#L138

@merlin-zaraza
Copy link

@merlin-zaraza , but the link you provided is not to our repository but to something else. In our repository, there's no such line: https://github.com/Kotlin/kotlinx-datetime/blob/master/core/common/src/Instant.kt#L138

Oh. My bad. You are right. Seems like this fork contains such format. Can you add this here?

@ilya-g
Copy link
Member

ilya-g commented Oct 13, 2021

@merlin-zaraza We expect a string in the extended ISO format of complete representation for calendar date and time of day (ISO 8601-1:2019, clause 5.4.2.1) as an input of the Instant.parse function. According to that format, +0000 is not a valid representation of a UTC offset.

@merlin-zaraza
Copy link

@ilya-g That's understandable and it's ok. The question is how to parse +0000 with this library? Java has DateTimeFormatter and DateTimeFormatterBuilder where you can construct custom format. Are there any plans to add it?

@ilya-g
Copy link
Member

ilya-g commented Oct 14, 2021

@merlin-zaraza Currently there's no way to parse such values because Instant.parse doesn't support this format. Later, when we implement custom formatting and parsing (see #58, #39), you'll be able to parse such values with a custom format pattern.

You can work around it currently by transforming an input value to the format Instant.parse supports, i.e. by inserting a : between hours and minutes in the offset designator part.

@tateisu
Copy link

tateisu commented Nov 14, 2021

I have same issue.
fixOffsetRepresentation works for +09, not works for +0900.

@dkhalanskyjb
Copy link
Collaborator

@tateisu sure, but why do you expect it to work for +0900? Who supports this format?

@tateisu
Copy link

tateisu commented Nov 15, 2021

After all, I stopped using kotlinx.datetime. It cannot support Android 7-.

@dkhalanskyjb
Copy link
Collaborator

dkhalanskyjb commented Nov 22, 2021

Having looked through the ISO, I see that +HHMM is the basic format, whereas we (like Java) only support the extended ISO format everywhere. We could potentially also support the basic format, but this would probably need to be a part of the overall effort of providing formatting/parsing.

@dkhalanskyjb dkhalanskyjb added formatters Related to parsing and formatting and removed enhancement New feature or request waiting for clarification Additional information is needed from the user labels Nov 22, 2021
@ilya-g
Copy link
Member

ilya-g commented Nov 22, 2021

@dkhalanskyjb In the basic format, date and time parts are also written without delimiters, e.g. 20210120T231501+0400. I suppose it's not what is needed here.

@dkhalanskyjb
Copy link
Collaborator

Good point. So, what is requested here is actually some mix of basic and extended formats.

@jeantuffier
Copy link

In my case, the api I work with at my company returns date with this format : "2021-01-01T22:00:00.000+0000".
I currently need to implement ax expect/actual strategy with kmm to let platform specific libraries parse the date.

@dkhalanskyjb
Copy link
Collaborator

Having to write expect/actual won't do at all.

        fun Instant.Companion.parseWithBasicOffset(string: String): Instant {
            var lastDigit = string.length
            while (lastDigit > 0 && string[lastDigit - 1].isDigit()) { --lastDigit }
            val digits = string.length - lastDigit // how many digits are there at the end of the string
            if (digits <= 2)
                return parse(string) // no issue in any case
            var newString = string.substring(0, lastDigit + 2)
            lastDigit += 2
            while (lastDigit < string.length) {
                newString += ":" + string.substring(lastDigit, lastDigit + 2)
                lastDigit += 2
            }
            return parse(newString)
        }

As a workaround, define this function in common code. For (somewhat) valid instants, it adds : between every two digits in the offset. For invalid instants, the errors won't look pretty though.

Example:

assertEquals("2019-12-31T06:02:01.010203040Z",
            Instant.parseWithBasicOffset("2020-01-01T00:01:01.010203040+1759").toString())
assertEquals("2019-12-31T06:02:01.010203040Z",
            Instant.parseWithBasicOffset("2020-01-01T00:01:01.010203040+17:59").toString())

@micbakos
Copy link

Thank you @dkhalanskyjb for the snippet.

dkhalanskyjb added a commit that referenced this issue Feb 20, 2024
Fixes #39
Fixes #58
Fixes #90
Fixes #128
Fixes #133
Fixes #139
Fixes #211
Fixes #240
Fixes #83
Fixes #276
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
formatters Related to parsing and formatting
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants
@tateisu @jeantuffier @ilya-g @merlin-zaraza @micbakos @dkhalanskyjb @nathanscb and others