【问题标题】:Validating Timestamp format yyyy-MM-dd'T'HH:mm:ssZ in java?在java中验证时间戳格式yyyy-MM-dd'T'HH:mm:ssZ?
【发布时间】:2014-09-24 06:16:38
【问题描述】:

我正在尝试使用 joda time-1.6.2 进行 时间戳 验证。请指出我的错误并帮助我。 代码

String timestamp = "2014-09-23T23:03:11Z";
String datePattern = "yyyy-MM-dd'T'HH:mm:ssZ";

try {
             DateTimeFormatter dateFormatter = DateTimeFormat.forPattern(datePattern);
             dateFormatter.parseDateTime(timestamp);

        } catch (Exception e) {
            LOG.info("Timestamp is invalid format" + e);
        }

例外

INFO: Timestamp is invalid formatjava.lang.IllegalArgumentException: Invalid format: "2014-09-23T23:03:11Z" is malformed at "Z"

【问题讨论】:

  • 时间戳中的Z应该是什么?是常数吗?
  • 我不能在 Z 中使用这种格式或模式
  • @AmilaIddamalgoda 为什么 T 像“T”?但在你的时间戳是 T?
  • @KickButtowski 这就是您在模式中指定文字字符 T 的方式,而不是向格式化程序指示字段类型。
  • 不需要格式化程序。您可以将符合 ISO 8601 的字符串直接传递给 DateTime 的构造函数,或传递给 DateTime.parse

标签: java date jodatime


【解决方案1】:

来自v1.6 API documentation

'Z' 输出不带冒号的偏移量,'ZZ' 输出带冒号的偏移量,'ZZZ' 或更多输出区域 id。

当您在模式中指定Z(不带单引号)时,时间戳中的值必须采用+HHMM-HHMM 格式作为与UTC 的数字偏移量。文字字符 Z 不是指定格式的有效输入。

例子:

  • 2014-09-23T23:03:11+0000
  • 2014-09-23T23:03:11-0500
  • 2014-09-23T23:03:11+0430

正如 Levit 在另一个答案中提到的那样,如果目标是在输入时间戳中接受文字“Z”而不将其视为时区(坏主意),那么 Z 字符可以在模式 (...'Z') 中使用单引号引起来。这类似于将日期组件与时间组件分开的文字“T”所做的事情。不建议将输入中的Z 视为文字,因为它具有含义,并且如果提供,时区是时间戳的重要组成部分。

【讨论】:

  • +1 这也很好地解释了Z 字符的含义!
【解决方案2】:

我非常怀疑将 Z 视为字面意思。 char Z 有一个含义,即零偏移量。Joda-Time version 1.6 的文档中提到了这段代码:

String timestamp = "2014-09-23T23:03:11Z";
DateTime dt = 
  ISODateTimeFormat.dateTimeNoMillis().parseDateTime(timestamp).withZone(DateTimeZone.UTC);
System.out.println(dt); // 2014-09-23T23:03:11.000Z

返回一个格式化程序,它结合了完整的日期和时间,没有毫秒, 用“T”分隔(yyyy-MM-dd'T'HH:mm:ssZZ)。时区偏移量是 'Z' 表示零,'±HH:mm' 表示非零。

现在让我们详细了解以下四种备选方案(已在 1.6.2 版本中进行了明确测试):

String timestamp = "2014-09-23T23:03:11Z";
DateTimeZone utc = DateTimeZone.UTC;

DateTime dt1 = ISODateTimeFormat.dateTimeNoMillis().parseDateTime(timestamp).withZone(utc);
System.out.println(dt1); // 2014-09-23T23:03:11.000Z (OK)

DateTime dt2 = new DateTime(timestamp, utc);
System.out.println(dt2); // 2014-09-23T23:03:11.000Z (OK)

DateTime dt3 =
  DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").parseDateTime(timestamp).withZone(utc);
System.out.println(dt3); //2014-09-23T21:03:11.000Z (WRONG!!!)

DateTime dt4 =
  DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZZ").parseDateTime(timestamp).withZone(utc);
// exception: Invalid format: "2014-09-23T23:03:11Z" is malformed at "Z"

结论:到目前为止将 Z 视为文字的其他答案是错误的,因为输入是在本地时区处理的,而不是偏移 UTC+00:00。使用构造函数或特定类IsoDateTimeFormat(为了清楚起见,我更喜欢后者)。

关于异常: 这是 2.0 版解决的错误,请参阅 release-notes。你最好更新你的库版本。

允许格式模式中的“Z”和“ZZ”将“Z”解析为“+00:00” [2827359]

【讨论】:

  • +1 表示将“Z”视为文字是不好的,因为它不会以这种方式将其解释为时区。我以为读者会认识到这一点,但我已经更新了我的答案。
  • +1 感谢您指出这一点,也更新了我的答案!你的似乎是最完整的答案/解释。
  • @Meno Hochschild 只是问题,它是格式错误的吗? 2015-11-17T00:00:00+0000Z ,可以同时拥有 +0000 和 Z 吗?
  • @Zilevav 这是双重信息(冗余),需要两个模式符号进行解析(必须不同 - SimpleDateFormat 中的“zXXX”,Joda-Time 不支持“X” )。不是一个好主意。更糟糕的是,如果输入中的偏移量是矛盾的(例如“...+01:00Z”),你会怎么做? SimpleDateFormat 只使用第一个偏移量“+01”并忽略第二个偏移量(Z = “00:00”),即使在严格模式下,我也测试过。
【解决方案3】:

为了不仅获得有效的时间戳格式,而且与 UTC 的偏移量为零,请使用

String timestamp = "2014-09-23T23:03:11Z";
DateTime dt = new DateTime(timestamp, DateTimeZone.UTC);

否则/陷阱

如果未将时间戳明确指定为 UTC,则可能会假定与本地时间的偏移为零。此外,虽然跟随可能是一种有效的模式,但它有点误导。

String timestamp = "2014-09-23T23:03:11Z";
String datePattern = "yyyy-MM-dd'T'HH:mm:ss'Z'";

正如 Meno 所描述的,这会将零时区偏移量视为文字(因此忽略它)。

还考虑增加 Meno Hochschild 的答案以更详细地解释这一点,因为我现在不允许删除我的答案(接受的答案)。

【讨论】:

猜你喜欢
  • 2017-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-18
  • 2022-11-29
相关资源
最近更新 更多