Joda Time bug还是我的错误? (Java Joda时间日期为字符串解析)

所以我在解析日期时遇到问题,使用JodaTime年表IslamicChronology年代IslamicChronology所以写了一个小例子来certificate我的问题。

这是代码:

 import org.joda.time.Chronology; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormat; import org.joda.time.chrono.IslamicChronology; import java.util.Date; /** * Test */ public class Test { public static void main(String[] args) { Date now = new Date(); String format = "dd MMM yyyy"; Chronology calendarSystem = IslamicChronology.getInstance(); DateTimeFormatter formatter = DateTimeFormat.forPattern(format).withChronology(calendarSystem); String nowAsString = formatter.print(now.getTime()); System.out.println("nowAsString = " + nowAsString); long parsedNowTs = formatter.parseMillis(nowAsString); String parsedNowTsAsString = formatter.print(parsedNowTs); } } 

并输出:

 nowAsString = 16 10 1430 Exception in thread "main" java.lang.IllegalArgumentException: Invalid format: "16 10 1430" is malformed at "10 1430" at org.joda.time.format.DateTimeFormatter.parseMillis(DateTimeFormatter.java:634) at test.Test.main(Test.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ... 

我认为问题是月份名称是数字,但我是对的吗? 有人有什么建议吗? 如果年表是格里高利的话,则无法重新创建。

提前致谢。

如果有人有兴趣…我找到了一个解决方法:

  • 创建一个新类,例如IslamicChronologyWithNames ,它在IslamicChronology包中委托给一个IslamicChronology实例
  • 修改一种方法; assemble(Fields fields) :调用委托的方法,然后将fields.monthOfYear(可能是dayOfWeek)设置为您自己的BasicMonthOfYearDateTimeField的子类
  • 然后, BasicMonthOfYearDateTimeField的子类可以在属性文件名中查找月份(或日期为DayOfWeek …)的名称。 子类需要在org.joda.time.chrono包中才能扩展BasicMonthOfYearDateTimeField

还有一个问题是Joda时间似乎在调用子类的方法之前validation了你解析的日期,比如getAsText(int fieldValue, Locale locale)并且因为它不知道你的类返回的月份名称,validation失败,所以从来没有调用方法。 我的解决方法是在这个类中有一个静态方法,它将日期作为带有伊斯兰月份名称的字符串转换为具有格里高利英语月份名称的字符串的日期。 因此,在调用parseDateTime()之前,调用静态方法,然后日期字符串通过validation。 然后,不要在convertText()方法中处理伊斯兰月份名称,而是使用子类中的默认格里高利实现:

 protected int convertText(String text, Locale locale) { return GJLocaleSymbols.forLocale(locale).monthOfYearTextToValue(text); } 

这应该工作! 希望对有同样问题的人有意义。

格式模板中的MMM表示缩写的月份名称。 数字月份索引应以MM表示。

在阅读了对dtsazza答案的评论之后,我首先意识到了你的实际问题。 🙂

我已经看了一下JODA源代码,似乎对伊斯兰计时码表的支持相当破碎。 首先,格式化程序不支持月份名称,因此模式MMM和MMMM格式化为月份编号,但根据DateTimeFormat的文档,缩写的月份名称应该用于MMM和MMMM的完整月份名称。

您的代码示例的一个问题是parseMillis始终使用ISO年表,尽管格式化程序已配置了另一个年表。 API文档中也提到了这一点,尽管不是特别直观。

如果我用parseMillis替换parseMillis ,我parseDateTime期望用于解析的时间顺序(至少文档说的是这样),但看起来好像实现忽略了配置的年表并继续这里的ISO年表。

您已将格式指定为dd MMM yyyy ; 根据API ,这意味着您需要以缩写字符串forms提供月份(在本例中为“Oct”)。 如果格式为dd MM yyyy则传入的输入将正确解析。

编辑:似乎我有点错过了你的观点。 您发现的是给定格式化程序的情况,

 long input = ...; // whatever formatter.parseMillis(formatter.print(input)); 

抛出一个例外。 虽然我看不出任何明确的保证,这应该始终有效,但我当然希望情况如此 – 所以是的,我支持你声称这是Joda本身可能存在的错误。

至少,如果这是预期的行为,应该有一些更明确的迹象表明它可能发生。