2

所以我在解析日期时遇到问题,使用 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)
    ...

我在想问题是月份名称是数字,但我是对的吗?有人有什么建议吗?如果年表是公历,则无法重新创建。

提前致谢。

4

3 回答 3

7

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

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

还有一个问题是,Joda time 似乎在调用子类的方法之前验证了您正在解析的日期getAsText(int fieldValue, Locale locale),因为它不知道您的类返回的月份名称,验证失败,因此从不调用这些方法。我的解决方法是在这个类中有一个静态方法,它将日期作为带有伊斯兰月份名称的字符串转换为日期作为带有公历英文月份名称的字符串。所以在调用之前parseDateTime(),调用静态方法,然后日期字符串通过验证。然后,不要在方法中处理伊斯兰月份名称,而是在convertText()子类中使用默认的 gregorian 实现:

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

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

于 2009-10-15T12:44:42.837 回答
5

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

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

我查看了 JODA 源代码,似乎对伊斯兰年表的支持已被破坏。首先,格式化程序不支持月份名称,因此将模式 MMM 和 MMMM 格式化为月份编号,尽管根据 DateTimeFormat 的文档,缩写月份名称应用于 MMM,完整月份名称用于 MMMM .

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

如果我替换parseMillisparseDateTime,我会期望年表用于解析(至少文档是这样说的),但看起来实现似乎忽略了配置的年表并继续使用 ISO 年表。

于 2009-10-06T14:30:28.947 回答
2

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

编辑:看来我有点错过了你的观点。您发现对于给定的格式化程序,

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

正在引发异常。虽然我看不到任何明确保证这应该始终有效,但我当然希望是这样 - 所以是的,我支持你的说法,即这可能是 Joda 本身的一个错误。

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

于 2009-10-06T14:30:17.063 回答