So, I know this is a problem well discussed upon and a lot of questions and answers (mostly concerning Joda) and also with the new class DateTimeFormatter and all that supports api levels above 26. But my concern is this:
So, I require to find #days between today and that date. When I write the code to parse one of them the other hits my catch block and vice versa, so I write a nested try/catch block to handle both the cases...something like this:
fun getFormattedDate(stringDate: String?): Long {
if (dueDateString.isNullOrEmpty())
return 0
val today = Calendar.getInstance().time
try {
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
val date = inputFormat.parse(dueDateString)
return if (date != null) {
val dueCalendar = Calendar.getInstance()
dueCalendar.time = date
getNoOfDays(today.time, dueCalendar.timeInMillis)
} else
0
} catch (ex: Exception) {
ex.showLog()
try {
val inputFormat1 = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH)
val date = inputFormat1.parse(dueDateString)
return if (date != null) {
val dueCalendar = Calendar.getInstance()
dueCalendar.time = date
getNoOfDays(today.time, dueCalendar.timeInMillis)
} else
0
} catch (exc: Exception) {
exc.showLog()
return 0
}
}
}
I am using this function to find #days between two dates:
fun getDueDateAfterParsing(dueDateString: String?): Long {
val today = ZonedDateTime.ofInstant(now(), ZoneId.systemDefault())
val dueDate = ZonedDateTime.parse(
dueDateString,
DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault())
)
return ChronoUnit.DAYS.between(today, dueDate)
}
I am pretty sure that the solution to this cannot be this complex. There are so many formats for ISO-8601 so i cant be writing try/catch blocks that fits for all cases right? So can anybody help me with the most simplest way I can get my way through this?
I have thought about regex too and most of them will end up saying Joda I am guessing, but at-least I want to be sure about what is the most optimal way or the best way of doing this.
Thanks in advance for any help.
You can use DateTimeFormatter
and the other classes from java.time, the modern Java date and time API, on Android API level 21 and up in two ways:
For both ways see the links at the bottom.
You don’t even need to specify a formatter.
String stringWeGot = "2020-09-03T17:03:11.719566Z";
Instant parsed = Instant.parse(stringWeGot);
System.out.println(parsed);
Output:
2020-09-03T17:03:11.719566Z
Or with your other example string:
String stringWeGot = "2021-03-05T18:30:00Z";
2021-03-05T18:30:00Z
The classes of java.time parse the most common ISO 8601 variants as their default, that is, without an explicit formatter. Presence or absence of from 0 through 9 decimals on the seconds is built in, even the presence or absence of the seconds themselves. Both Instant
and OffsetDateTime
can be used in the manner shown in the code.
Warning! If you do opt for one or more formatters for one reason or another, never hardcode Z
as a literal in the format pattern string. Z
is an offset (of zero) from UTC and must be parsed as such, or you get incorrect results on the vast majority of Android devices.
Also when it comes to counting days, java.time is far superior to the old and poorly designed classes like Calendar
. EDIT: Your method for counting whole days until the due date in the device time zone is correct. Just for reference, my way of doing it would be:
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime today = ZonedDateTime.now(zone);
ZonedDateTime dueDate = parsed.atZone(zone);
long daysUntilDue = ChronoUnit.DAYS.between(today, dueDate);
System.out.println(daysUntilDue);
Using your example string of 2021-03-05T18:30:00Z
and running in Europe/Copenhagen time zone just now the result was:
181
java.time
was first described.java.time
to Java 6 and 7 (ThreeTen for JSR-310).