2

I need to convert a dateTime String to millis and I am using ThreeTenABP for this, but the OffSetDateTime.parse is unable to parse the dateTime String which is for ex. "2020-08-14T20:05:00" and giving the following exception.

Caused by: org.threeten.bp.format.DateTimeParseException: Text '2020-09-22T20:35:00' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: DateTimeBuilder[, ISO, null, 2020-09-22, 20:35], type org.threeten.bp.format.DateTimeBuilder 

I have already searched through similar questions but could not find the exact solution.

Below is the code that I am using in Kotlin.

val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss", Locale.ROOT) val givenDateString = event?.eventDateTime val timeInMillis = OffsetDateTime.parse(givenDateString, formatter) .toInstant() .toEpochMilli() 
2

1 Answer 1

3

The problem is the missing offset in the String that you are trying to parse to an OffsetDateTime. An OffsetDateTime cannot be created without a ZoneOffset but no ZoneOffset can be derived from this String (one could just guess it's UTC, but guessing is not suitable in such a situation).

You can parse the String to a LocalDateTime (a representation of a date and a time of day without a zone or an offset) and then add / attach the desired offset. You don't even need a custom DateTimeFormatter because your String is of ISO format and can be parsed using the default built-in formatter:

fun main() { // example String val givenDateString = "2020-09-22T20:35:00" // determine the zone id of the device (you can alternatively set a fix one here) val localZoneId: ZoneId = ZoneId.systemDefault() // parse the String to a LocalDateTime val localDateTime = LocalDateTime.parse(givenDateString) // then create a ZonedDateTime by adding the zone id and convert it to an OffsetDateTime val odt: OffsetDateTime = localDateTime.atZone(zoneId).toOffsetDateTime() // get the time in epoch milliseconds val timeInMillis = odt.toInstant().toEpochMilli() // and print it println("$odt ==> $timeInMillis") } 

this example code produces the following output (pay attention to the trailing Z in the datetime representation, that's an offset of +00:00 hours, the UTC time zone, I wrote this code in the Kotlin Playground and it seems to have UTC time zone ;-) ):

2020-09-22T20:35Z ==> 1600806900000 

Please note that I tried this with java.time and not with the ThreeTen ABP, which is obsolete to use for many (lower) Android versions now, since there's Android API Desugaring. However, this shouldn't make a difference because your example code threw exactly the same exception when I tried it first, which means ThreeTen is not to blame for this.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the detailed answer! The ZoneOffset makes much sense since it is a UTC. Though I used ThreeTenABP as it is backward compatible and java.time requires min API 26.
@RKB you're welcome. Have a look at the link in the last paragraph of my answer, java.time (at least a large subset of it) can now be used in lower API levels as well if you are using the required gradle plugin. Thanks for accepting and voting.
Nice answer! Just some additional info: Since the goal is to calculate epoch millis, val odt: OffsetDateTime = localDateTime.atZone(zoneId).toOffsetDateTime() can be written as val zdt: ZonedDateTime = localDateTime.atZone(ZoneOffset.UTC). After that, the millis could be calculated either as zdt.toEpochSecond().1000 or zdt.toInstant().toEpochMilli(). In summary, converting to ZonedDateTime instead of OffsetDateTime would have made the code slightly cleaner.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.