Kotlin Unparseable date - ParseException error - PullRequest
0 голосов
/ 01 февраля 2019

Я вижу следующую ошибку при попытке разобрать строку даты, может ли кто-нибудь указать мне правильное направление для разбора этой строки даты?

"2019-01-22T12:43:01Z"

Ошибка:

java.text.ParseException: Unparseable date: "2019-01-22T12:43:01Z"

код:

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"
} 

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

java.time

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)
}

Давайте попробуем:

fun main() {
    println(timeSince("2019-01-22T12:43:01Z"))
}

Это только что напечатано:

236 ч назад

Я использую java.time, современный Java-интерфейс даты и времени.По сравнению со старыми классами Date и, что не менее важно, SimpleDateFormat мне гораздо приятнее работать.Приведенный выше метод выдаст DateTimeParseException, если переданная ему строка не соответствует формату ISO 8601.Для большинства целей это, вероятно, лучше, чем возвращать 0 h ago.Метод допускает наличие и отсутствие (до 9) десятичных знаков в секундах, поэтому принимает, например, 2019-01-22T12:43:01.654321Z.

Разве нам не нужен форматер?Нет. Я пользуюсь тем фактом, что ваша строка имеет формат ISO 8601, формат, который современные классы даты и времени анализируют (и также печатают) по умолчанию.

Хотелось бы использовать ChronoUnit и Instant

Редактировать:

Я бы хотел использовать ChronoUnit & Instant, но для этого требуется минимум V26 Android.Мой текущий минимум составляет 23.

java.time прекрасно работает и на старых устройствах Android.Для этого требуется как минимум Java 6 .

  • В Java 8 и более поздних версиях и на более новых устройствах Android (начиная с уровня API 26) современный API поставляется встроенным.
  • В Java 6 и 7 получают ThreeTen Backport, бэкпорт современных классов (ThreeTen для JSR 310; см. Ссылки внизу).
  • На (более старых) Android используется версия ThreeTen для AndroidBackport.Это называется ThreeTenABP.И убедитесь, что вы импортируете классы даты и времени из org.threeten.bp с подпакетами.

Что пошло не так в вашем коде?

Я вижу две ошибки в коде в вашем вопросе:

  1. Как уже указывал 10 芒 轻 胜 马 胜 в этом ответе , ваш формат ожидает 4 части между T и Z, разделенные двоеточиями, но вашСтрока имеет только три части.С SimpleDateFormat использование двух SS для доли секунды также неправильно, так как верхний регистр S предназначен для миллисекунд, поэтому имеет смысл только три SSS (в отличие от современного DateTimeFormatter S для дробисекунды, поэтому любое число (до 9 SSSSSSSSS) имеет смысл).
  2. Вы рассматриваете Z в строке как литерал.Это смещение UTC, равное нулю, и его необходимо проанализировать как таковое, иначе вы получите неправильное время (в подавляющем большинстве JVM).

Links

0 голосов
/ 01 февраля 2019

Поскольку ваш ввод не содержит миллисекунд, вы можете удалить :SS из шаблона:

const val SERVER_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'" 

И я бы предложил использовать пакет java.time.

...