Java 防止;24“;时间中的小时值(不含秒)

Java 防止;24“;时间中的小时值(不含秒),java,Java,我曾请求编写一个方法,该方法将执行基本的时间验证。 时间必须分为一个间隔:00:00-23:59,并且没有秒。实际上秒是被禁止的。 我对使用Java8日期/时间api(如果有)的解决方案感兴趣 因为我还没有找到解决方案,所以我提出了以下解决方案: private void validateTimeWithoutSeconds(String timeValue) throws Exception { boolean hasSeconds = false; try {

我曾请求编写一个方法,该方法将执行基本的时间验证。 时间必须分为一个间隔:00:00-23:59,并且没有秒。实际上秒是被禁止的。 我对使用Java8日期/时间api(如果有)的解决方案感兴趣

因为我还没有找到解决方案,所以我提出了以下解决方案:

private void validateTimeWithoutSeconds(String timeValue) throws Exception {
    boolean hasSeconds = false;
    try {
        DateTimeFormatter.ofPattern("HH:mm:ss").parse(timeValue);
        hasSeconds = true;
    } catch (Exception e) {
    }

    if (hasSeconds) {
        String err1 = "\Error : Time has seconds.";
        throw new Exception(err1);
    }

    try {
        LocalTime.parse(timeValue, DateTimeFormatter.ISO_TIME);
    } catch (Exception e) {
        String err2 = "Error. Time does not belong to the interval of 00:00-23:59";
        throw new Exception(err2);
    }
}

使用字符串正则表达式有一个简单的解决方案,因为您的输入是字符串形式的,我认为这是一个更好的方法。使用以下示例:


timeValue.matches(([01]?[0-9]| 2[0-3]):[0-5][0-9])”

您发现了一个谜

  • HH:mm
    的自定义格式模式允许
    24:00
    作为有效值
  • 使用预定义的格式化程序不接受24:00并引发
    DateTimeParseException
此格式化程序接受
24:00
作为
00:00

DateTimeFormatter f = DateTimeFormatter.ofPattern( "HH:mm" ); // Accepts 24:00 as meaning 00:00.
 DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_TIME ;  // Expects 00:00 to 23:59.
当遇到
24:00

DateTimeFormatter f = DateTimeFormatter.ofPattern( "HH:mm" ); // Accepts 24:00 as meaning 00:00.
 DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_TIME ;  // Expects 00:00 to 23:59.
HH:mm
allow
24:00
违反了,似乎在做
kk:mm
的工作:

k时钟小时数(1-24)24

小时数(0-23)0

我建议你提交一份bug报告。在Azul Systems基于OpenJDK的Zulu JVM上使用Java 10.0.2时,我看到了与您相同的行为,在MacBook Pro Retina上使用macOS High Sierra运行。而IdeOne.com在运行Java8时也表现出同样的行为

解决方法:使用默认格式化程序,而不是定义自己的格式 首先,如果只允许小时和分钟,但不允许秒

否则,请使用内置格式设置程序解析输入字符串

您期望的具有无效输入的特定异常的陷阱:

输入
24:00
会引发我们预期的异常:

线程“main”java.time.format.DateTimeParseException中的异常:无法分析文本“24:00”:HourOfDay的值无效(有效值0-23):24

顺便说一下,您可以选择以秒为单位拒绝输入,而不是以秒为单位拒绝输入

lt.toString():12:34


要解决此问题,请使用
with ResolverStyle(ResolverStyle.STRICT)
创建模式。创建新模式时,默认值为
ResolverStyle.SMART
,它对超出范围的数字进行一些基本猜测

关于另一个答案中提到的
DateTimeFormatter.ISO_LOCAL_TIME
,它使用了
STRICT
,这就是为什么看起来相同的模式有不同的行为(模式相同,但解析器样式不同)。从:

返回的格式化程序没有覆盖时间顺序或区域。它使用
严格的
解析器样式

混淆的原因是,内置常量模式使用
STRICT
,而自定义模式默认为
SMART
,这似乎出乎意料


有关不同解析器样式的更多信息:

如果您希望格式为HH:mm,为什么要使用HH:mm:ss或ISO_-TIME解析,而不是使用HH:mm解析?只需使用
DateTimeFormatter.ofPattern(“HH:mm”).parse(timeValue)(后续:为什么混合使用DateTimeFormatter.parse和LocalTime.parse?)为什么不通过在“:”处拆分字符串将字符串解析为整数并进行验证?不幸的是,“DateTimeFormatter.ofPattern(“HH:mm”).parse(24:00);”不会引发异常。我已经试过了。看到正则表达式总是很有用的,谢谢。我只是想知道是否有一个像您这样简洁的解决方案,但是使用Java8日期/时间API,我没有像您这样的例外。这就是全部的秘密。DateTimeFormatter f=模式的DateTimeFormatter.of(“HH:mm”);字符串v=“24:00”;尝试{LocalTime lt=LocalTime.parse(v,f);System.err.println(“v:+lt.format(f));}catch(DateTimeParseExceptionö1){System.err.println(“greška:+1.getMessage());}catch(Exceptionö2){System.err println(“greška:+2.getMessage());}输出为:v:00:00@dobrivoje事实上,我现在明白你的秘密了。您的粘贴没有抛出异常。定义
HH:mm
格式模式的行为不同于。我不知道为什么。@dobrivoje我现在已经确定了答案。最初我没有运行我发布的代码示例,并且无意中测试了
LocalTime.parse
使用的默认格式化程序。我很抱歉用不正确的信息误导你。谢谢。就是这样:DateTimeFormatter.ISO_LOCAL_TIME正确验证时间,而DateTimeFormatter.of模式(“HH:mm”)则不正确。实际上,DateTimeFormatter.ISO_LOCAL_TIME正确地解析有秒和无秒,ODE不允许24显示为输入。
LocalTime lt = LocalTime.parse( "12:34:56" ).truncatedTo( ChronoUnit.MINUTES ) ; // Lop off any seconds or fractional second. Returns value in whole minutes.