在 Kotlin 中解析持续时间字符串

Parsing a Duration String in Kotlin

我正在开发一个 Android 应用程序,我需要解析这种形式的持续时间字符串“00:00:00.000”(例如:“00:00:38.47”或“00:03” :27.11").

我的最终目标是将此字符串转换为带毫秒的总秒数的两倍以获得进度百分比。

我已经研究过 SimpleDateFormatter,但我在理解它的工作原理或我应该如何使用它时遇到了一些问题。

我试过这个:

val timeString = "00:01:08.83"
val df = SimpleDateFormat("HH:mm:ss.SS")
df.parse(timeString)?.seconds!!.toFloat() // Returns 8.00, I want to have 68.83 for this example string

那么有 simple/efficient 的方法吗?

  val time = LocalTime.parse("00:01:08.83", DateTimeFormatter.ofPattern("HH:mm:ss.SS"))

  println(time.toSecondOfDay())
  println(time.toNanoOfDay())
  println(time.toNanoOfDay().toFloat() / 1_000_000_000)

输出:

68
68830000000
68.83

您使用的方法 getSeconds() returns 仅分析时间的秒数,并且已弃用。
如果你不能在你的 Android 应用中使用 LocalTime.parse() 因为它需要 API 级别 26,那么拆分时间字符串并通过乘法解析它每个部分都有适当的因素:

val timeString = "00:01:08.83"
val factors = arrayOf(3600.0, 60.0, 1.0, 0.01)
var value = 0.0
timeString.replace(".", ":").split(":").forEachIndexed { i, s -> value += factors[i] * s.toDouble() }
println(value)

将打印:

68.83

您还可以创建一个扩展函数:

fun String.toSeconds(): Double {
    val factors = arrayOf(3600.0, 60.0, 1.0, 0.01)
    var value = 0.0
    this.replace(".", ":").split(":").forEachIndexed { i, s -> value += factors[i] * s.toDouble() }
    return value
}

并使用它:

val timeString = "00:01:08.83"
val seconds = timeString.toSeconds()
println(seconds)

java.time.Duration

如链接问题中所示,有几种方法可以做到这一点。恐怕没有一种客观上最好的方法。

您最有可能在持续时间内使用 java.time 中的 Duration,即现代 Java 日期和时间 API。

遗憾的是,没有办法将您的字符串直接解析为 Duration。我的偏好是将您的字符串修改为 ISO 8601 格式,Duration class 知道如何解析的格式。我相信你会把我的 Java 代码翻译成更漂亮的 Kotlin 代码。

    String timeString = "00:01:08.83";
    String isoDurationString = timeString
            .replaceFirst("(\d+):(\d{2}):(\d{2}(?:\.\d+)?)", "PTHMS");
    Duration dur = Duration.parse(isoDurationString);
    System.out.println(dur);

此片段的输出是:

PT1M8.83S

正则表达式功能强大但难以阅读。圆括号表示我想保留在修改后的字符串中的组;我在替换字符串中将它们称为 </code> 等。 <code>(?:\.\d+) 是一个 非捕获 组,我不需要在替换中使用它。非捕获组之后的 ? 表示它不需要存在(因此表达式也只匹配 00:01:08)。

对于百分比,又有一些选项。 Duration 对象可以直接乘以 100 并且由于 Java 9 可以相互除法。假设您还没有使用 Java 9,我可能会根据毫秒或纳秒(而不是带分数的秒)进行计算。例如:

    long totalMilliseconds = dur.toMillis();
    System.out.println(totalMilliseconds);

68830

然而,为了回答你的问题,我将如何在 float 中转换为秒:

    float totalSeconds = ((float) dur.toNanos()) / TimeUnit.SECONDS.toNanos(1);
    System.out.println(totalSeconds);

68.83