Reputation: 2669
I'm seeing the following error when trying to parse a date string, can anyone point me in the right direction to parse this date string?
"2019-01-22T12:43:01Z"
Error:
java.text.ParseException: Unparseable date: "2019-01-22T12:43:01Z"
Code:
package ch02.ex1_1_HelloWorld
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.Date
import java.util.concurrent.TimeUnit
const val SERVER_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss:SS'Z'"
val sdf = SimpleDateFormat(SERVER_TIME_FORMAT, Locale.US)
fun main(args: Array<String>) {
timeSince("2019-01-22T12:43:01Z")
}
fun timeSince(dateStr: String) {
var diff : Long = 0
try {
diff = sdf.parse(dateStr).time - Date().time
} catch (e: Exception) {
print(e)
}
"${TimeUnit.HOURS.convert(diff, TimeUnit.MILLISECONDS)} h ago"
}
Upvotes: 3
Views: 5435
Reputation: 2184
My original value from server is:
2021-04-08T11:27:40.278Z
You can simply, make this shorter. With kotlin, 2021:
// Read the value until the minutes only
val pattern = "yyyy-MM-dd'T'HH:mm"
val serverDateFormat = SimpleDateFormat(pattern, Locale.getDefault())
// Format the date output, as you wish to see, after we read the Date() value
val userPattern = "dd MMMM, HH:mm"
val userDateFormat = SimpleDateFormat(userPattern, Locale.getDefault())
val defaultDate = serverDateFormat.parse(INPUT_DATE_STRING)
if ( defaultDate != null ) {
val userDate = userDateFormat.format(defaultDate)
textView.text = userDate
}
Result:
08 April, 11:27
Upvotes: 0
Reputation: 86314
import java.time.Instant;
import java.time.temporal.ChronoUnit;
fun timeSince(dateStr: String): String {
val diffHours = ChronoUnit.HOURS.between(Instant.parse(dateStr), Instant.now())
return "%d h ago".format(diffHours)
}
Let’s try it out:
fun main() {
println(timeSince("2019-01-22T12:43:01Z"))
}
This just printed:
236 h ago
I am using java.time, the modern Java date and time API. Compared to the old classes Date
and not least SimpleDateFormat
I find it so much nicer to work with. The method above will throw a DateTimeParseException
if the string passed to it is not in ISO 8601 format. For most purposes this is probably better than returning 0 h ago
. The method is tolerant to presence and absence of (up to 9) decimals on the seconds, so accepts for example 2019-01-22T12:43:01.654321Z
.
Don’t we need a formatter? No. I am taking advantage of the fact that your string is in ISO 8601 format, the format that the modern date and time classes parse (and also print) as their default.
ChronoUnit
and Instant
Edit:
I wish I could use ChronoUnit & Instant, but it requires a min V26 of Android. My current min is 23.
java.time works nicely on older Android devices too. It just requires at least Java 6.
org.threeten.bp
with subpackages.I see two bugs in the code in your question:
T
and Z
, separated by colons, but your string has only three parts there. With SimpleDateFormat
using two SS
for fraction of second is also wrong since uppercase S
is for milliseconds, so only three SSS
would make sense (by contrast, with the modern DateTimeFormatter
S
is for fraction of second, so any number (up to 9 SSSSSSSSS
) makes sense).Z
in the string as a literal. It’s a UTC offset of zero and needs to be parsed as such, or you will get an incorrect time (on the vast majority of JVMs).java.time
.java.time
was first described.java.time
to Java 6 and 7 (ThreeTen for JSR-310).Upvotes: 5
Reputation: 28289
Since your input does not contain milli seconds, you can remove the :SS
in the pattern:
const val SERVER_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"
And I would suggest to use java.time
package.
Upvotes: 5