Java: 自定义时间戳格式:验证微秒精度的格式

3
我的目标是创建一个Java类,可以处理以下两个要求:
(A) 1. 验证时间戳的格式是否与期望的格式匹配。 CCYY-MM-DD'T'hh:mm:ss'.0000000000+'uh:um" 例如:期望的格式不是静态的。它可能是以下任何一种格式: "2013-09-10T18:30:20.123456+10:00" 或者 "2013-09-10T18:30:20.123+10:00"。 精度和值并不重要,只有格式很重要。
(B) 2. 验证时间戳是否在特定范围内。 例如:验证时间戳是否在“2013-09-10 18:27”和“2013-09-10 18:33”之间。(验证仅限于分钟级精度)(可能会有+/-2分钟的变化)
问题是如何使用Java类验证自定义时间戳的微秒精度?
这个类的两个参数将分别是:
1)期望的时间戳格式作为字符串
2)时间戳值作为字符串
根据来自各种搜索结果的分析,我了解到:
1. Java(默认情况下)不解析/格式化微秒级别的时间戳(我使用了SimpleDateFormat)。
2. 如果在毫秒数位置给出6位数字,它会重新计算出秒数,并更新日期格式,新的日期格式将具有3位毫秒级精度。
3. 我还看到一条线程建议使用java.sql.Timestamp。
尝试了这个方法但不起作用。我无法将我的strTimestamp 2013-09-10T18:30:20.123456+10:00转换为Timestamp对象。
Timestamp ts = Timestamp.valueOf(strTimestamp); 
java.lang.IllegalArgumentException: 
 Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]

我无法将输入格式转换为时间戳对象。


我有一个使用正则表达式验证的解决方法:

2013-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9]).[0-9][0-9][0-9][0-9][0-9][0-9]\+10:00

这个正则表达式的问题在于,我期望的时间戳格式并不固定。因此我需要为每种模式使用一个正则表达式。
因此,我正在尝试找出是否有任何稳健的解决方案在Java中,即使期望的格式发生变化也可以自给自足。

请将您的问题限制在一个问题之内。如果您有多个问题,请分开提问。 - Bohemian
我编辑了帖子,以针对一个具体的问题... - bijju
3个回答

0

java.sql.Timestamp 对你没有帮助,因为它本质上是一个 java.util.Date

代码相当简单,只要使用正确的格式字符串与 SimpleDateFormat 一起使用即可让其轻松完成任务。以下是完整的工作解决方案:

public static boolean isNear(String timestamp, int microPlaces, Date near, int minutes) {
    if (!timestamp.matches(".*\\.\\d{" + microPlaces + "}\\D.*") {
        return false;
    }
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSSZ");
    try {
        Date date = sdf.parse(timestamp.replaceAll(":(?=\\d\\d$)", ""));
        return Math.abs(date.getTime() - near.getTime()) <= minutes * 60000;
    } catch (ParseException ignore) {
        return false; // string was not of correct format
    }
}

这可能不完全符合您的想法 - 如果不是,您应该能够将其用作您想要的基础。关键点如下:

  • S格式字符串表示“微秒”,并且不需要所有数字 - 因此您的时间戳可以有任意数量的数字
  • Java 6需要从时区中删除冒号。Java 7不需要这样做 - 使用X格式字符串而不是Z
  • 无法从输入解析日期会抛出ParseException - 对此事件进行处理
  • 我选择使API为范围提供中央日期和+/-分钟值。您可能需要传递两个日期 - 由您决定。如果您这样做,请使用Date.before()Date.after()进行比较。

以下是一些测试代码,测试您的示例和一些边缘情况:

public static void main(String[] args) throws Exception {
    Date near = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm").parse("2013-09-10T18:32");
    System.out.println(isNear("2013-09-10T18:30:20.123456+10:00", near, 2));
    System.out.println(isNear("2013-09-10T18:30:20.123+10:00", near, 2));
    System.out.println(isNear("2013-09-10T18:10:20.123+10:00", near, 1));
    System.out.println(isNear("XXXX-09-10T18:10:20.123+10:00", near, 1));
}

输出:

true
true
false
false

要求是验证实际时间戳格式是否与期望的微秒精度时间戳格式匹配。正如您所提到的,上述代码不需要微秒中的所有数字,时间戳可以有任意数量。因此,此代码无法处理要求。当期望的时间戳有6个数字时,该类应强制使用所有6个数字。如果没有,则返回false/异常。当期望的时间戳有3个数字时,该类应仅强制使用3个数字。如果没有,则返回false/异常。 - bijju
所以您想检查是否只有3或6位微秒?即如果不是3或6,则返回false? - Bohemian
期望的格式有以下几种: 2013-09-17T10:31:30.123+10:00 或者 2013-09-17T10:31:30.123456+10:00 或者 2013-09-17T10:31:30.123456789+10:00期望的格式将作为参数传递给类。它应该完全匹配所期望的格式。 - bijju
以上有三个(3/6/9),预期的格式只有这三种。 - bijju
我已经修改了该方法,使其还能接受纳秒位数。使用正则表达式来断言指定的位数是否正确。只有当微秒位数正确且时间戳解析并接近指定日期时,该方法才会返回true。 - Bohemian
显示剩余2条评论

0

我也在努力寻找这个问题的答案。由于我无法添加评论到Bohemian的回答中,我想提醒大家SimpleDateFormat中的'S'模式不是用于微秒而是用于毫秒。这意味着对于模式"yyyy-MM-dd'T'hh:mm:ss.SSSSSSZ",提供的微秒数字将被解析为毫秒。 因此,前三位数字将被传递为XXX秒,并将其值添加到日期中。因此我们可能会出现约16分钟的错误。


0

Java 8中的java.time

JSR 310Java 8中定义了一个新的java.time包。它的日期时间类可以精确到纳秒,小数点后有9位数字。

java.time包受Joda-Time的启发,但完全重新架构。概念相似。

与Joda-Time一样,java.time包使用ISO 8601格式作为其默认解析和格式化方式。因此,您可以输入或输出字符串,例如2013-09-10T18:30:20.123456789+10:00

Java 8的早期版本现已可用。正式发布应该是本月。

一个将此包移植到早期Java版本的项目正在进行中。我不知道它目前的状态或成功情况。这个移植项目独立于Oracle和OpenJDK项目。

毫秒

旧的捆绑类java.util.Date和.Calendar使用毫秒精度。

同样,优秀的Joda-Time库也是毫秒精度。

因此,小数秒中的数字不足以满足您的需求。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接