Java 时间戳接受破折号

Java Timestamp accepting dashes

我为 HHMMSS.FFFFF 格式化了一个正则表达式: ^([0-1]\d|2[0-3])([0-5]\d)([0-5]\d).(\d{5})

并用于创建这样的 SimpleDateFormat

 String format = "HHMMSS.FFFFF";
 SimpleDateFormat sdf = new SimpleDateFormat(format);

然后尝试使用以下数据创建时间戳

new Timestamp(sdf.parse("1-1212.00000).getTime());

正在使用

121212.00000

正如预期的那样好。 然后尝试用这样的

来做
1-1212.00000

而且它仍然没有抛出异常。 在 regex101 上测试正则表达式时,破折号无效。

为什么 Timestamp 接受带有该正则表达式的破折号?

格式"HHMMSS.FFFFF"是:
HH = 一天中的小时 (0-23)
MM = 年月
SS = 毫秒
FFFFF = 星期几 (DoWiM)

我不认为那是你的本意。但是让我们一起去吧。

记住,所有其他字段都是默认值,即
年 = 1970
月日 = 1
DayOfWeek = 星期日
分钟 = 0
第二 = 0

输入 000100.00001 解析为 1970-01-04 00:00:00.0,因为 1/4/1970 是第一个 (DoWiM=1) 星期日 (默认 DayOfWeek) 一月 (Month=1) 午夜 (Hour=0, Milli=0).
这是你的基线。

输入121212.00000解析为1970-11-29 12:00:00.012,因为Month=12使1970-12-06成为1970年12月的第一个星期日,而FFFFF=0则是前一周那。

输入 1-1212.00000 解析为 1969-10-26 01:00:00.212 因为它解析为 H=1, M=-1, S=212, F=0,即 M=-1 是 1 月之前的 2 个月,而 1969-11-02 是第一个星期日1969 年 11 月,1969-10-26 比那早一周。

I know I didn't ask this but is HHmmss.SSSSS what I should be using?

你现在问了,谢谢你的提问。

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HHmmss.SSSSS");
    String timeString = "121212.00000";
    LocalTime time = LocalTime.parse(timeString, dtf);
    System.out.println(time);

这会打印

12:12:12
java.time 中的

LocalTime 具有纳秒精度(秒数最多 9 位小数),但其 toString 方法不会打印分数为零的分数。例如121212.34567,解析为12:12:12.345670。让我们也用破折号试试你的字符串,1-1212.00000。结果是 java.time.format.DateTimeParseException: Text '1-1212.00000' could not be parsed at index 0。如您所料,格式化程序拒绝解析第二个数字为破折号的小时数。这也意味着你在解析中有很好的验证,所以你不再需要任何正则表达式(regex)。

TimestampSimpleDateFormat class 都已经过时了,尽管后者是两者中更麻烦的一个。另外 SimpleDateFormat 只支持毫秒精度,它无法正确解析 5 位小数的秒数。在 java.time 包中找到现代替代品。使用 DateTimeFormatter 进行解析。我假设您想将没有日期的时间保存到 SQL 数据库中。如果是这样,请使用 time 的 SQL 数据类型和 Java 中的 LocalTimePreparedStatement.setObject() 将接受 LocalTime 进行保存。如果您的数据库列的类型为 timestamp 且无法更改,请改用 LocalDateTime

虽然 Andreas 在评论中解释了为什么您建议的 HHmmss.SSSSS 格式模式字符串不适用于 SimpleDateFormat,但它 可以与 DateTimeFormatter。这里大写 S 表示秒的小数,所以 SSSSS 表示五位小数(否则许多格式模式字母对两个格式化程序具有相同的含义,只是不是全部)。

问题:我可以在 Java 6 中使用 java.time 吗?

是的,以上大部分都适用于您的 JavaSE 1.6,只是 PreparedStatement.setObject() 不行。您需要将 ThreeTen Backport 添加到您的项目中。这是 java.time 到 Java 6 和 7 的反向移植(“ThreeTen”,因为 java.time 首次在 JSR-310 中描述)。请参阅下面的 link。

要保存到您的 SQL 数据库,您需要转换为老式的 java.sql.Timestampjava.sql.Time。对于时间戳,您还需要一个日期。例如:

    LocalDate epochDate = LocalDate.ofEpochDay(0);
    Timestamp timeToSave 
            = DateTimeUtils.toSqlTimestamp(LocalDateTime.of(epochDate, time));

我选择了 1970 年 1 月 1 日这个纪元日期,因为这也是将您的时间字符串正确解析为 Timestamp 的结果。我认为您的 DICOM 可能会给您一个您想要使用的日期。 DateTimeUtils 也有一个 toSqlTime 方法用于将 LocalTime 转换为 java.sql.Time。 Link 到下面的文档。

Links