解析为 LocalTime 模式 mm:ss.S
Parse to LocalTime pattern mm:ss.S
如何从字符串中解析 LocalTime,例如mm:ss.S 格式的“10:38.0”?我很难改变格式。
public static LocalTime parseTime(String time) {
return localTime = LocalTime.parse(time, DateTimeFormatter.ofPattern("mm:ss.S"));
}
获取错误
ISO 类型 java.time.format.Parsed
java.time.format.DateTimeParseException:无法解析文本“10:38.2”:无法从 TemporalAccessor 获取本地时间:{MinuteOfHour=10,MicroOfSecond=200000,MilliOfSecond=200,NanoOfSecond=200000000,SecondOfMinute=38},
问题是,mm:ss
并不是真正的当地时间。这更像是短跑比赛时间。发生该错误是因为翻译要求为过去的小时数提供一个值,并且 none 可用('no hours' 在这里被解释为:他们不在模式中,而不是:“他们失踪了,因此让我们假设有 0 小时").
解决这个问题的一种 hacky 方法是将模式更改为 [HH:]mm:ss
- []
表示可选输入。现在含义发生了变化:10:20
被解释为(通过可选的输入方面)00:10:20
的 shorthand 并且 是 可解析为 LocalTime .
但是,也许 LocalTime
并不是您在这里寻找的东西;如果这确实描述了测量事件所经过的时间,那么您正在寻找 Duration
,而不是 LocalTime
。不幸的是,将 10:20
解析为 10 分 20 秒的持续时间并非易事,API 只是不支持它(从 DTFormatter
对象到达那里的唯一方法是 通过 LocalTime,够疯狂了)。
我相信你想要:.ofPattern("H:mm.s")
public static LocalTime parseTime(String time) {
return LocalTime.parse(time, DateTimeFormatter.ofPattern("H:mm.s"));
}
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
DateTimeFormatterBuilder#parseDefaulting
您可以使用 DateTimeFormatterBuilder#parseDefaulting
将一天中的小时默认为零。
但是,在常识中,10:38.0
代表一个时长。您可以通过找到解析的 LocalTime
和 LocalTime.MIN
.
之间的持续时间来获得 Duration
对象
演示:
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String str = "10:38.0";
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.appendPattern("mm:ss.S")
.toFormatter(Locale.ENGLISH);
LocalTime time = LocalTime.parse(str, dtf);
System.out.println(time);
Duration duration = Duration.between(LocalTime.MIN, time);
System.out.println(duration);
}
}
输出:
00:10:38
PT10M38S
了解有关 modern Date-Time API* from Trail: Date Time 的更多信息。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
java.time.Duration.parse()
正如其他几个人正确而明智地指出的那样,您的示例字符串 10:38.0
看起来更像是一段时间,一段持续时间。不像一天中午夜后 10 分钟多一点的时间。所以 LocalTime
不是在这里使用的正确 class。使用 Duration
。并将字符串解析为 Duration
对象。
不过Duration
class只支持解析ISO 8601格式。 ISO 8601 格式类似于 PT10M38.0S
,持续 10 分 38.0 秒(或者例如 PT10M38S
或 PT10M38.00000S
,它们也有效)。有更多方法可以克服此限制。 Arvind Kumar Avinash 已经在他的回答中展示了一个。我的方法是在解析之前转换字符串:
public static Duration parseTime(String time) {
String iso = time.replaceFirst("^(\d+):(\d+(?:\.\d*)?)$", "PTMS");
return Duration.parse(iso);
}
让我们试试看:
Duration dur = parseTime("10:38.0");
System.out.println(dur);
输出为:
PT10M38S
您看到 Duration
也以 ISO 8601 格式打印回来。
根据您希望进行的进一步处理,您可能会在 class 的文档中找到许多有用的方法; link 下面。
time.replaceFirst("^(\d+):(\d+(?:\.\d*)?)$", "PTMS")
的工作原理: 我正在使用正则表达式来匹配您的字符串:
^
:匹配字符串的开头。
(\d+)
:捕获组匹配一位或多位数字。圆括号表示捕获组。我将在下面的替换中需要此功能。
:
:一个冒号(确实如此)。
(\d+(?:\.\d*)?)
:一组捕获的数字,可选地后跟一个点和零个或多个其他数字。 (?:
表示我使用的非捕获组的开头,因为我不需要在替换中单独使用它。 ?
在非捕获组之后表示它是可选的(因此 38
没有分数也适用于秒数)。
$
: 匹配你的字符串结尾
在我的替换字符串中、PTMS
、</code>和<code>
表示第一和第二捕获组行进的任何内容,是将 10
和 38.0
插入结果字符串以获得 PT10M38.0S
.
带有外部库的更好的解决方案:Time4J
使用上面的非平凡正则表达式来使您的字符串和 Duration.parse()
相遇并不是完美的解决方案。 Time4J 库支持基于模式的持续时间解析。因此,如果您可以容忍外部依赖,请考虑使用它。详见Time4J作者Meno Hochshield的回答。
链接
a) class DateTimeFormatter
无法解析像 mm:ss.S
这样没有小时的表达式,因为这样的解析器试图将其解释为时间点,而不是持续时间。缺少小时是将结果解析为 LocalTime
.
实例的固定要求
b) 您可能需要持续时间,而不是 LocalTime
。好吧,java.time
确实有一个名为 java.time.Duration
的 class 但它只能格式化和解析类 ISO-8601 表达式的子集,例如: PT10M38.2S
你想要的模式不支持。对不起。
c) 有些人建议妥协:将 LocalTime
解释为一种持续时间(不是真的!)然后使用默认小时值解析表达式,最后评估分钟和秒等等。但是,只有当您永远不会获得大于 59 分钟或 59 秒的时间分量值时,这种 hacky 解决方法才会起作用。
d) 我的外部图书馆 Time4J supports pattern-based printing and parsing of durations. Example using the class net.time4j.Duration.Formatter:
@Test
public void example() throws ParseException {
TemporalAmount ta =
Duration.formatter(ClockUnit.class, "mm:ss.f")
.parse("10:38.2")
.toTemporalAmount();
System.out.println(LocalTime.of(5, 0).plus(ta)); // 05:10:38.200
}
该示例还演示了通过转换方法 toTemporalAmount()
到 Java-8-class 的桥梁,例如 LocalTime
。如果您使用 net.time4j.PlainTime
代替,那么桥接当然不是必需的。
此外,time4j-duration-class 的众多特性之一是在表达式包含不符合标准时钟方案(如 10 分 68 秒(= 11 分钟)的时间分量时控制归一化+ 8 秒)。
@Test
public void example2() throws ParseException {
net.time4j.Duration dur =
Duration.formatter(ClockUnit.class, "mm:ss.f")
.parse("10:68.2")
.with(Duration.STD_CLOCK_PERIOD); // normalizing
System.out.println(PlainTime.of(5, 0).plus(dur)); // 05:11:08.200
}
如何从字符串中解析 LocalTime,例如mm:ss.S 格式的“10:38.0”?我很难改变格式。
public static LocalTime parseTime(String time) {
return localTime = LocalTime.parse(time, DateTimeFormatter.ofPattern("mm:ss.S"));
}
获取错误
ISO 类型 java.time.format.Parsed java.time.format.DateTimeParseException:无法解析文本“10:38.2”:无法从 TemporalAccessor 获取本地时间:{MinuteOfHour=10,MicroOfSecond=200000,MilliOfSecond=200,NanoOfSecond=200000000,SecondOfMinute=38},
问题是,mm:ss
并不是真正的当地时间。这更像是短跑比赛时间。发生该错误是因为翻译要求为过去的小时数提供一个值,并且 none 可用('no hours' 在这里被解释为:他们不在模式中,而不是:“他们失踪了,因此让我们假设有 0 小时").
解决这个问题的一种 hacky 方法是将模式更改为 [HH:]mm:ss
- []
表示可选输入。现在含义发生了变化:10:20
被解释为(通过可选的输入方面)00:10:20
的 shorthand 并且 是 可解析为 LocalTime .
但是,也许 LocalTime
并不是您在这里寻找的东西;如果这确实描述了测量事件所经过的时间,那么您正在寻找 Duration
,而不是 LocalTime
。不幸的是,将 10:20
解析为 10 分 20 秒的持续时间并非易事,API 只是不支持它(从 DTFormatter
对象到达那里的唯一方法是 通过 LocalTime,够疯狂了)。
我相信你想要:.ofPattern("H:mm.s")
public static LocalTime parseTime(String time) {
return LocalTime.parse(time, DateTimeFormatter.ofPattern("H:mm.s"));
}
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
DateTimeFormatterBuilder#parseDefaulting
您可以使用 DateTimeFormatterBuilder#parseDefaulting
将一天中的小时默认为零。
但是,在常识中,10:38.0
代表一个时长。您可以通过找到解析的 LocalTime
和 LocalTime.MIN
.
Duration
对象
演示:
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String str = "10:38.0";
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.appendPattern("mm:ss.S")
.toFormatter(Locale.ENGLISH);
LocalTime time = LocalTime.parse(str, dtf);
System.out.println(time);
Duration duration = Duration.between(LocalTime.MIN, time);
System.out.println(duration);
}
}
输出:
00:10:38
PT10M38S
了解有关 modern Date-Time API* from Trail: Date Time 的更多信息。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
java.time.Duration.parse()
正如其他几个人正确而明智地指出的那样,您的示例字符串 10:38.0
看起来更像是一段时间,一段持续时间。不像一天中午夜后 10 分钟多一点的时间。所以 LocalTime
不是在这里使用的正确 class。使用 Duration
。并将字符串解析为 Duration
对象。
不过Duration
class只支持解析ISO 8601格式。 ISO 8601 格式类似于 PT10M38.0S
,持续 10 分 38.0 秒(或者例如 PT10M38S
或 PT10M38.00000S
,它们也有效)。有更多方法可以克服此限制。 Arvind Kumar Avinash 已经在他的回答中展示了一个。我的方法是在解析之前转换字符串:
public static Duration parseTime(String time) {
String iso = time.replaceFirst("^(\d+):(\d+(?:\.\d*)?)$", "PTMS");
return Duration.parse(iso);
}
让我们试试看:
Duration dur = parseTime("10:38.0");
System.out.println(dur);
输出为:
PT10M38S
您看到 Duration
也以 ISO 8601 格式打印回来。
根据您希望进行的进一步处理,您可能会在 class 的文档中找到许多有用的方法; link 下面。
time.replaceFirst("^(\d+):(\d+(?:\.\d*)?)$", "PTMS")
的工作原理: 我正在使用正则表达式来匹配您的字符串:
^
:匹配字符串的开头。(\d+)
:捕获组匹配一位或多位数字。圆括号表示捕获组。我将在下面的替换中需要此功能。:
:一个冒号(确实如此)。(\d+(?:\.\d*)?)
:一组捕获的数字,可选地后跟一个点和零个或多个其他数字。(?:
表示我使用的非捕获组的开头,因为我不需要在替换中单独使用它。?
在非捕获组之后表示它是可选的(因此38
没有分数也适用于秒数)。$
: 匹配你的字符串结尾
在我的替换字符串中、PTMS
、</code>和<code>
表示第一和第二捕获组行进的任何内容,是将 10
和 38.0
插入结果字符串以获得 PT10M38.0S
.
带有外部库的更好的解决方案:Time4J
使用上面的非平凡正则表达式来使您的字符串和 Duration.parse()
相遇并不是完美的解决方案。 Time4J 库支持基于模式的持续时间解析。因此,如果您可以容忍外部依赖,请考虑使用它。详见Time4J作者Meno Hochshield的回答。
链接
a) class DateTimeFormatter
无法解析像 mm:ss.S
这样没有小时的表达式,因为这样的解析器试图将其解释为时间点,而不是持续时间。缺少小时是将结果解析为 LocalTime
.
b) 您可能需要持续时间,而不是 LocalTime
。好吧,java.time
确实有一个名为 java.time.Duration
的 class 但它只能格式化和解析类 ISO-8601 表达式的子集,例如: PT10M38.2S
你想要的模式不支持。对不起。
c) 有些人建议妥协:将 LocalTime
解释为一种持续时间(不是真的!)然后使用默认小时值解析表达式,最后评估分钟和秒等等。但是,只有当您永远不会获得大于 59 分钟或 59 秒的时间分量值时,这种 hacky 解决方法才会起作用。
d) 我的外部图书馆 Time4J supports pattern-based printing and parsing of durations. Example using the class net.time4j.Duration.Formatter:
@Test
public void example() throws ParseException {
TemporalAmount ta =
Duration.formatter(ClockUnit.class, "mm:ss.f")
.parse("10:38.2")
.toTemporalAmount();
System.out.println(LocalTime.of(5, 0).plus(ta)); // 05:10:38.200
}
该示例还演示了通过转换方法 toTemporalAmount()
到 Java-8-class 的桥梁,例如 LocalTime
。如果您使用 net.time4j.PlainTime
代替,那么桥接当然不是必需的。
此外,time4j-duration-class 的众多特性之一是在表达式包含不符合标准时钟方案(如 10 分 68 秒(= 11 分钟)的时间分量时控制归一化+ 8 秒)。
@Test
public void example2() throws ParseException {
net.time4j.Duration dur =
Duration.formatter(ClockUnit.class, "mm:ss.f")
.parse("10:68.2")
.with(Duration.STD_CLOCK_PERIOD); // normalizing
System.out.println(PlainTime.of(5, 0).plus(dur)); // 05:11:08.200
}