用simpleDataFormat解析负时间字符串

pxq42qpu  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(340)

在使用SimpleDataFormat解析时间字符串时,我看到了一些让我感到困惑的输出。因此,考虑到以下情况:

public class NewMain 
{
    public static void main( String[] args )
    {
        String str1 = "00:00:03";
        parseStr(str1);

        String str2 = "-00:00:03";
        parseStr(str2);

        String str3 = "00:59:59";
        parseStr(str3);

        String str4 = "-00:59:59";
        parseStr(str4);

        String str5 = "01:00:00";
        parseStr(str5);

        String str6 = "-01:00:00";
        parseStr(str6);
    }

    private static void parseStr(String aStr)
    {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        Calendar cal = sdf.getCalendar();
        Date date = cal.getTime();
        System.out.println("SimpleDateFormat.getCalendar.getTime: " + date.toString());

        try
        {
            Date dee = sdf.parse(aStr);
            String dStr = dee.toString();
            System.out.println("SimpleDateFormat.parse("+aStr+") = " + dStr);
        }
        catch (ParseException ex)
        {
            ex.printStackTrace();
        }
        System.out.println("");
    }
}

和输出:

SimpleDateFormat.getCalendar.getTime: Sun Dec 08 10:00:28 CST 1940
SimpleDateFormat.parse(00:00:03) = Thu Jan 01 00:00:03 CST 1970

SimpleDateFormat.getCalendar.getTime: Sun Dec 08 10:00:28 CST 1940
SimpleDateFormat.parse(-00:00:03) = Thu Jan 01 00:00:03 CST 1970

SimpleDateFormat.getCalendar.getTime: Sun Dec 08 10:00:28 CST 1940
SimpleDateFormat.parse(00:59:59) = Thu Jan 01 00:59:59 CST 1970

SimpleDateFormat.getCalendar.getTime: Sun Dec 08 10:00:28 CST 1940
SimpleDateFormat.parse(-00:59:59) = Thu Jan 01 00:59:59 CST 1970

SimpleDateFormat.getCalendar.getTime: Sun Dec 08 10:00:28 CST 1940
SimpleDateFormat.parse(01:00:00) = Thu Jan 01 01:00:00 CST 1970

SimpleDateFormat.getCalendar.getTime: Sun Dec 08 10:00:28 CST 1940
SimpleDateFormat.parse(-01:00:00) = Wed Dec 31 23:00:00 CST 1969

前两个负数解析为给定时间,不带“-”。但是字符串“-01:00:00”解析为完全不同的时间。看起来解析器正在从1970年1月1日减去它。我很困惑,因为“-00:00:03”和“-00:59:59”没有这个效果!
任何帮助都将不胜感激!

xnifntxz

xnifntxz1#

java.time.duration文件

我同意sotirios delimanolis的假设,例如,字符串表示时间量,比如持续时间。在许多情况下,这可能是积极的,也可能是消极的。如果这个假设是正确的,使用 Duration 在 java 。
一个限制 Duration 只有ISO8601格式的字符串可以直接解析为 Duration . 所以我使用正则表达式将字符串转换为ISO8601格式。

private static void parseStr(String aStr)
{
    // Convert string to ISO 8601 format
    String isoStr = aStr.replaceFirst(
            "^([+-]?)(\\d{2}):(\\d{2}):(\\d{2})$", "$1PT$2H$3M$4S");
    // Parse to Duration
    Duration dur = Duration.parse(isoStr);
    // Print
    System.out.format("Duration.parse(%s) = %s%n", aStr, dur);

    System.out.println();
}

使用此方法声明 main 方法打印:

Duration.parse(00:00:03) = PT3S

Duration.parse(-00:00:03) = PT-3S

Duration.parse(00:59:59) = PT59M59S

Duration.parse(-00:59:59) = PT-59M-59S

Duration.parse(01:00:00) = PT1H

Duration.parse(-01:00:00) = PT-1H
``` `Duration` 同时打印iso 8601格式。这种格式对许多人来说是不寻常的,但很简单。阅读示例 `PT3S` 一段3秒的时间。
我带着减号通过字符串转换,因为它在ISO8601中是完全允许的。所以我们解析的持续时间都有预期的符号。
这个 `Duration` 类是java.time的一部分,后者是现代java日期和时间api。
编辑:如果你喜欢,两个 `System.out` 语句可以合并为一个:

System.out.format("Duration.parse(%s) = %s%n%n", aStr, dur);

我只是放了一个双人床 `%n` 有两条新线。

### 反对意见:我不能将java.time用于我的Java7?

此外,我们将在java7停留在可预见的未来。
time可以很好地与Java7配合使用。它至少需要Java6。
在Java8和更高版本以及更新的android设备上(api级别26),现代api是内置的。
在(非android)java6和java7中获得了三个10的backport,即现代类的backport(三个10用于jsr310;请参见底部的链接)。
在旧的android上,要么使用desugaring,要么使用android版本的threeten backport。它叫3TENABP。在后一种情况下,请确保从导入日期和时间类 `org.threeten.bp` 有分装的。

### 你一定要处理吗?

我们的测试人员是有点邪恶的笑,并决定看看会发生什么,如果他们进入一个负。所以,可能性很小,但现在他已经把它曝光了,我们必须处理它。
虽然我不了解你们的组织,但我来自哪里,挑战这些要求是可以的。如果一个负的时间量是有意义的,并且对你的用户来说是一个有用的概念,那么处理它。如果说不通的话,就修改要求,明确不允许有任何标志。当你的测试人员(他似乎做得很好)键入一条错误信息时,发出一条错误信息,而不是试图理解那些荒谬的信息。

### 你的代码里发生了什么?

我真希望我知道为什么“-”会有那种效果。。。
第一, `SimpleDateFormat` (我想是错误的)把字符串当作一天中的时间,而不是持续时间。第二,a `SimpleDateFormat` 在标准设置下,接受一天中的负小时是令人困惑的。例如: `-00:00:03` 取一天中的平均小时数=-0,小时分钟数=0,分钟秒数=3。因为-0和0是一样的,所以只有00:00:03。日期默认为1970年1月1日。
在 `-01:00:00` 一天的时间是–1.–1是0点之前的一个小时,因此与前一个晚上的23点相同。日期仍然默认为1970年1月1日。所以你得到1969年12月31日23:00:00。
在所有情况下,任何减号都是用来否定一天中的某个小时的,只有在我认为你的测试仪意味着否定整个持续时间的情况下。

### 链接

oracle教程:date time解释如何使用java.time。
java规范请求(jsr)310,其中 `java.time` 第一次被描述。
三十后港工程 `java.time` 到Java6和Java7(jsr-310为310)。
通过desugaring提供Java8+API
threetenabp,android版threeten backport
问:如何在android项目中使用threetenabp,有非常透彻的解释。
维基百科文章:iso 8601
jm2pwxwz

jm2pwxwz2#

负时间。 -00:59:59 没有道理。如果您的api从客户机应用程序获得了这样的时间,那么要么丢弃它,要么教育客户机应用程序的所有者纠正它。另一个选择是在删除负号后解析字符串。
注意,api的日期时间 java.util 以及它们的格式化api, SimpleDateFormat 过时且容易出错。建议完全停止使用它们,并切换到现代日期时间api。

import java.time.LocalTime;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(parseStr("00:00:03"));
        System.out.println(parseStr("00:59:59"));
        System.out.println(parseStr("01:00:00"));
    }

    static LocalTime parseStr(String str) {
        return LocalTime.parse(str);
    }
}

输出:

00:00:03
00:59:59
01:00

在trail:date-time了解有关现代日期时间api的更多信息。
注意:无论出于何种原因,如果您必须坚持使用Java6或Java7,您可以使用threeten backport,它将大部分java.time功能向后移植到Java6和Java7。
如果您正在为一个android项目工作,并且您的android api级别仍然不符合java-8,请检查通过desugaring提供的java8+api以及如何在android项目中使用threetenabp。
下面给出了删除负号后如何解析字符串:

import java.time.LocalTime;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(parseStr("00:00:03"));
        System.out.println(parseStr("00:59:59"));
        System.out.println(parseStr("01:00:00"));
        System.out.println(parseStr("-00:00:03"));
        System.out.println(parseStr("-00:59:59"));
        System.out.println(parseStr("-01:00:00"));
    }

    static LocalTime parseStr(String str) {
        if (str.charAt(0) == '-') {
            str = str.substring(1);
        }
        return LocalTime.parse(str);
    }
}

输出:

00:00:03
00:59:59
01:00
00:00:03
00:59:59
01:00

如果你是说 Duration (可以是负数)而不是时间,检查 Duration#toString 了解持续时间是如何表示的。
使用旧api:

import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Main {
    public static void main(String[] args) throws ParseException {
        // Test
        System.out.println(parseStr("00:00:03"));
        System.out.println(parseStr("00:59:59"));
        System.out.println(parseStr("01:00:00"));
        System.out.println(parseStr("-00:00:03"));
        System.out.println(parseStr("-00:59:59"));
        System.out.println(parseStr("-01:00:00"));
    }

    static String parseStr(String str) throws ParseException {
        if (str.charAt(0) == '-') {
            str = str.substring(1);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(sdf.parse(str));
    }
}

输出:

00:00:03
00:59:59
01:00:00
00:00:03
00:59:59
01:00:00

请注意,日期时间对象不存储格式信息。如果您希望以特定格式打印日期时间对象,可以使用格式化api(例如。 DateTimeFormatter 在现代api和 SimpleDateFormat 在遗留api中)。这个 LocalTime#toString 返回iso-8601格式的字符串 HH:mm:ss 因此,如果它是预期的格式,则不需要使用 DateTimeFormatter .

相关问题