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

时间:2009-10-06 14:27:37

标签: java date parsing jodatime

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

以下是代码:

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)
    ...

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

提前致谢。

3 个答案:

答案 0 :(得分:7)

如果有人有兴趣......我找到了解决方法:

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

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

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

那应该有用!希望对遇到同样问题的人有意义。

答案 1 :(得分:5)

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

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

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

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

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

答案 2 :(得分:2)

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

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

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

正在抛出异常。虽然我看不到任何明确的保证这应该始终有效,但我当然希望是这样的 - 所以是的,我支持你声称这是Joda中可能存在的错误本身。

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