Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何解析只有4位数的年份_Java_Jodatime_Date Parsing - Fatal编程技术网

Java 如何解析只有4位数的年份

Java 如何解析只有4位数的年份,java,jodatime,date-parsing,Java,Jodatime,Date Parsing,我用乔达的时间来分析这些年: private DateTime attemptParse(String pattern, String date) { DateTimeFormatter parser = DateTimeFormat.forPattern(pattern).withLocale(Locale.ENGLISH); DateTime parsedDateTime = parser.parseLocalDateTime(date).toDateTime

我用乔达的时间来分析这些年:

private DateTime attemptParse(String pattern, String date) {
        DateTimeFormatter parser = DateTimeFormat.forPattern(pattern).withLocale(Locale.ENGLISH);
        DateTime parsedDateTime = parser.parseLocalDateTime(date).toDateTime(WET);
        return parsedDateTime;
    }
我正在尝试解析多种格式:
“yyyy-MM-dd”、“yyy-MMM-dd”、“yyy-MMM-dd”、“yyy-MMM”等、“yyyy”
。一个坏了,我就试试下一个

当字符串实际上只有4位数字时(例如:
“2016”
),它就像一个符咒。问题是我有时会收到这样的邮件:
“201400”
。Joda Time将其与
“yyyy”
模式匹配,并返回一个年份为
201400
的日期


我想避免使用丑陋的if来检查
year>9999
。使用Joda Time有什么方法可以做到这一点吗?

要解析多种格式,您可以创建大量的
DateTimeParser
实例,并在一个格式化程序中加入所有实例(而不是一个接一个地尝试)

这将需要一个
DateTimeFormatterBuilder
,它还将用于在输入中强制执行特定数量的数字(不幸的是,没有办法强制执行特定数量的数字,就像只使用
DateTimeFormat.forPattern()

首先,创建大量
org.joda.time.format.DateTimeParser
实例(每个可能的模式一个):

然后用所有这些模式创建一个数组,并用它创建一个
DateTimeFormatter

// create array with all the possible patterns
DateTimeParser[] possiblePatterns = new DateTimeParser[] { p1, p2, p3 };

DateTimeFormatter parser = new DateTimeFormatterBuilder()
    // append all the possible patterns
    .append(null, possiblePatterns)
    // use the locale you want (in case of month names and other locale sensitive data)
    .toFormatter().withLocale(Locale.ENGLISH);
我还使用了
Locale.ENGLISH
(因为您在问题的代码中也使用了它)。此区域设置表示月份名称将使用英语(因此
MMM
可以解析
Jan
Sep
等值)。通过此操作,您可以解析输入:

System.out.println(parser.parseLocalDateTime("2014")); // OK
System.out.println(parser.parseLocalDateTime("201400")); // exception
System.out.println(parser.parseLocalDateTime("2014-10-10")); // OK
System.out.println(parser.parseLocalDateTime("201400-10-10")); // exception
System.out.println(parser.parseLocalDateTime("2014 Jul")); // OK
System.out.println(parser.parseLocalDateTime("201400 Jul")); // exception
当年份为2014年时,代码运行良好。当它是
201400
时,它抛出一个
java.lang.IllegalArgumentException
,例如:

java.lang.IllegalArgumentException:无效格式:“201400”在“00”处格式不正确

DateTimeFormatter
是不可变的且线程安全的,因此您不需要每次调用验证方法时都创建它。您可以在方法之外创建它(例如在
静态final
字段中)

这比每次执行验证时创建一个格式化程序,并在发生异常时转到下一个格式化程序要好。创建的格式化程序已经在内部执行了该操作,将转到下一个模式,直到找到一个有效的模式为止(如果所有模式都失败,则抛出异常)


Java新的日期/时间API Joda Time处于维护模式,正在被新的API所取代,因此我不建议使用它启动新项目。甚至在文章中也提到:“请注意,Joda Time被认为是一个基本上“完成”的项目。没有计划进行重大的增强。如果使用Java SE 8,请迁移到Java.Time(JSR-310)。”

如果您不能(或不想)从Joda Time迁移到新API,可以忽略此部分

如果使用<强> java 8 < />,请考虑使用这更容易

如果您使用的是Java6或7,则可以使用,这是Java8新的日期/时间类的一个很好的后端口。对于Android,您还需要(更多关于如何使用它的信息)

下面的代码适用于这两种情况。 唯一的区别是包名(在Java8中是
Java.time
,而在ThreeTen Backport(或Android的ThreeTenABP)中是
org.ThreeTen.bp
),但类和方法是相同的

这个新API比以前的API严格得多,因此格式化程序只能使用精确的位数(请注意,有些类与Joda Time非常相似):

此代码适用于
2014
,但适用于
201400
201
(或任何其他不含4位数字的值)时会引发异常:

java.time.format.DateTimeParseException:无法在索引0处分析文本“201400”

这样,验证代码就可以处理字符串数组。


只有一个细节:解析日期时,Joda Time会在输入没有某些字段时设置默认值(如月份变为一月,日期变为1,小时/分钟/秒设置为零,等等)

如果只是验证输入,则不需要返回任何内容。只要检查是否抛出异常,您就会知道输入是否有效

但是,如果您只需要年份值,可以使用:

如果要将年份值设置为
int

Year year = Year.parse("2014", parser);
int yearValue = year.getValue(); // 2014

但是如果你想得到一个日期对象,你需要手动设置默认值——新的API非常严格,不会自动设置这些值。在这种情况下,必须使用
DateTimeFormatterBuilder
设置默认值

我还将其解析为
LocalDateTime
,例如:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // string pattern
    .appendPattern("yyyy")
    // default month is January
    .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
    // default day is 1
    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
    // default hour is zero
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    // default minute is zero
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    // set locale
    .toFormatter(Locale.ENGLISH);
// create LocalDateTime
System.out.println(LocalDateTime.parse("2014", fmt)); // 2014-01-01T00:00
System.out.println(LocalDateTime.parse("201400", fmt)); // exception

您可以选择您想要的任何值作为字段的默认值,并使用任何值。

您要说的是Jodatime应该以某种方式猜测它应该将“201400”解析为2014。我认为这不在图书馆的范围之内。您应该自己预处理数据,例如使用:

String normalizedDate = String.format("%4s", date).trim();

为什么不只是解析<代码>子串(日期,0, 4)< /Cord>?@ Grffy狗狗,因为我不认为201400是一个有效的日期,所以我必须抛出一个异常。字符串的长度不是告诉你吗?这可能是比我的预处理答案更好的想法;实际上,我不想改为DateTimeFormatterBuilder,因为我简化了这个问题。我试图解析多种格式:“yyyy-MM-dd”、“yyy-MMM-dd”、“yyy-MMM-dd-dd”、“yyy-MMM”、(等)、“yyyy”。当无效日期“201400”出现时,它会被转换,我希望Jodatime抛出一个异常。如果我要切换到DateTimeFormatterBuilder,我需要使用它创建每个日期模式:/@micdcar在这种情况下,您可以编辑您的问题,以便我可以相应地更新我的答案吗?@Hugo谢谢您的回答,它确实解决了问题。霍
Year year = Year.parse("2014", parser);
int yearValue = year.getValue(); // 2014
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // string pattern
    .appendPattern("yyyy")
    // default month is January
    .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
    // default day is 1
    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
    // default hour is zero
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    // default minute is zero
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    // set locale
    .toFormatter(Locale.ENGLISH);
// create LocalDateTime
System.out.println(LocalDateTime.parse("2014", fmt)); // 2014-01-01T00:00
System.out.println(LocalDateTime.parse("201400", fmt)); // exception
String normalizedDate = String.format("%4s", date).trim();