【问题标题】:Unknown pattern character 'x', when using SimpleDateFormat使用 SimpleDateFormat 时的未知模式字符“x”
【发布时间】:2017-11-19 04:23:16
【问题描述】:

我正在尝试使用SimpleDateFormatDate 格式化为String,而我使用的模式就是这个

"yyyy-MM-dd'T'HH:mm:ss.SSSxxx"

但是当到达这条线

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSxxx");

我得到以下异常:

java.lang.IllegalArgumentException:未知模式字符“x”在 java.text.SimpleDateFormat.validatePatternCharacter(SimpleDateFormat.java:323) 在 java.text.SimpleDateFormat.validatePattern(SimpleDateFormat.java:312) 在 java.text.SimpleDateFormat.(SimpleDateFormat.java:365) 在 java.text.SimpleDateFormat.(SimpleDateFormat.java:258)

我试图实现的格式是 “2017-06-16T12:19:59.001+02:00

根据documentation,这个模式应该可以工作 怎么了?

编辑 为了澄清,我尝试了 xxx 和 XXX

如果是 XXX,我会得到 java.lang.IllegalArgumentException: Unknown pattern character 'X'

【问题讨论】:

  • 您使用大写的X 附加了模式,而文档告诉它应该是小写的x。但随后异常堆栈再次告知小写x。你能澄清一下吗?
  • 时区的“X”是 SimpleDateFormat 中相对较新的功能。如果您在仅支持 Java 6 的 Android 版本上运行它,那么它将无法工作。
  • 是的,但我尝试了大写和小写。
  • @BalázsNemes 有什么选择?
  • 我真的不知道。这是一个完全有效的问题。与Java SE相反,旧版本的Android不支持X。我不知道为什么人们会无缘无故地否决这个问题。我要对这个问题投赞成票。

标签: java android simpledateformat android-date


【解决方案1】:

请参阅下面的更新。

不幸的是,关于大写的X,文档 [在问题和这个答案的时候] 是错误的。由于documentation 似乎有changed significantlyxX 相关,我将继续在此声明,现在它说支持X(大写)(从API 级别1 开始),但是x(小写)根本没有提到。 docs used to 也没有提到 X

检查Android source code(请参阅 validateFormat())表明该版本中仅识别字母 GyMdkHmsSEDFwWahKzZLc,尽管文档声称自 API 级别 1 起已支持 X。这解释了原因你会收到IllegalArgumentException: Unknown pattern character 'X'

有关历史详情,请参阅this bug report

同时,您必须找到一种解决方法,这取决于您需要解析的输入类型。例如。 the OP's answer.

更新:X 仅适用于 Nougat+。

文档中有now been fixed 添加了“支持的(API 级别)”列,这表明仅从 API 级别 24 开始支持 X。推测 OP 的 IllegalArgumentException 是由于在24 之前的设备,因为文档之前没有说明支持的 API 级别。

【讨论】:

    【解决方案2】:

    我相信我在issue at GitHub 中找到了答案:

    你是对的,Android 使用ZZZZZ 来生成时区,例如 +01:00(就像 Java 中的 XXX)。现在,您能否尝试使用ApiClient#setDatetimeFormat 方法自定义日期时间格式以 让它在 Android 上运行?

    以petstore样本为例:

    // import io.swagger.client.Configuration;
    // import io.swagger.client.ApiClient;
    // import java.text.SimpleDateFormat;
    
    // Customize for the default ApiClient
    Configuration.getDefaultApiClient().setDatetimeFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"));
    
    // Customize for a new ApiClient
    ApiClient apiClient = new ApiClient();
    apiClient.setDatetimeFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"));
    // Use the new ApiClient
    PetApi api = new PetApi(apiClient);
    api.getPetById(new Long(1));
    

    显然,我必须使用:

    yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ  
    

    【讨论】:

    • 这解决了我的问题。我正在使用正则表达式检查它是否为 ISO8601:regex101.com/r/b3GJso/1,然后覆盖parse(dateString) 以在github url here 中使用规范化字符串,否则只需使用super.parse(dateString)
    【解决方案3】:

    您需要的模式是"yyyy-MM-dd'T'HH:mm:ss.SSSXXX",但它在异常中提到了小写x。看起来你在某个地方有错字。

    【讨论】:

    • 我尝试了大写和小写,错误编辑问题以澄清
    • 另外,在他们在文档中显示的示例中,他们拥有“yyyy-MM-dd'T'HH:mm:ss.SSSXXX”2001-07-04T12:08:56.235-07:00
    • 你需要绝对使用大写。就像我提到的那样。使用大写X 时有什么例外?
    • java.lang.IllegalArgumentException:未知模式字符“X”
    【解决方案4】:

    改用这个:

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ");

    【讨论】:

      【解决方案5】:

      如果有人会在这里寻找答案,如何为 API 低于 24 的设备使用模式 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" 格式化字符串。

      使用 Java DateTimeFormatter 和 OffsetDateTime,因为它不需要像 SimpleDateFormat 那样提供输入模式

      Java 代码:

       public static String formatISO8601String(String string) {
              DateTimeFormatter desiredFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
              OffsetDateTime dateTime = OffsetDateTime.parse(string);
              return dateTime.format(desiredFormat);
          }
      

      Kotlin 代码:

      fun formatISO8601String(string: String): String {
              val desiredFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
              val dateTime = OffsetDateTime.parse(string)
              return dateTime.format(desiredFormat)
          }
      

      【讨论】:

        【解决方案6】:

        我认为您正在寻找“yyyy-MM-dd'T'HH:mm:ss.SSSZ”

        将日期格式更改为

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 或

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

        这可能对你有帮助

        【讨论】:

        • Z 是 RFC 风格的时区,而另一个是 ISO 风格的时区。我认为这些通常不会起作用(它们可能适用于某些特殊情况)。
        • 小z用于一般时区
        • SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.UK); String formattedDate = sdf.format(new Date());
        猜你喜欢
        • 1970-01-01
        • 2011-01-25
        • 2015-04-07
        • 1970-01-01
        • 1970-01-01
        • 2011-02-15
        • 1970-01-01
        • 1970-01-01
        • 2017-10-23
        相关资源
        最近更新 更多