Java 日期格式为 00 天/月

Pat*_*rik 5 java date zero date-parsing dayofmonth

我的日期为String,但有时它没有有效的日期或月份(值为零,00)。

例子:

String value = "03082017";
Run Code Online (Sandbox Code Playgroud)

然后我这样做:

    String day = value.substring(0,2);
    String month = value.substring(2,4);
    String year = value.substring(4,8);

    if(day.equals("00")) {
        day = "01";
    }
    if(month.equals("00")) {
        month = "01";
    }

    value = day + month + year;
Run Code Online (Sandbox Code Playgroud)

这适用于示例String

现在我有这个字符串:

String value = "00092017" //ddMMyyyy 
Run Code Online (Sandbox Code Playgroud)

然后我的代码将00日期转换为01.

这适用于模式ddMMyyyy,但现在是我的问题:我可以有不同的模式:ddMMyyyyMMddyyyyyyyy/dd/MM

我的解决方案是首先检查模式(例如MMddyyyy),然后查看我的值03092017ddMMyyyy)并将数字放入我的日期字符串中,该字符串位于模式中的 dd 位置。

所以代码有模式ddMMyyyy但值为03092017( MMddyyyy)

String day = "03";
.....
Run Code Online (Sandbox Code Playgroud)

我的代码:

public void doSomething(String valueWithDate, String pattern){
    // now I become: 
    // valueWithDate = 01092017
    // pattern = ddMMyyyy

    String day = valueWithDate.substring(0,2);
    String month = valueWithDate.substring(2,4);
    String year = valueWithDate.substring(4,8);

    //Works I get my information but what is when I get other pattern/value? for example:
    // valueWithDate = 09082017
    // pattern = MMddyyyy
    // now I want my information again, but day is not on substring 0,2
}
Run Code Online (Sandbox Code Playgroud)

小智 4

如果您使用的是Java 8,则可以使用新的 java.time API。与旧的 API 相比,它更简单、漏洞更少、更不容易出错

如果您使用的是Java <= 7,则可以使用ThreeTen Backport,这是 Java 8 的新日期/时间类的绝佳向后移植。对于Android,您还需要ThreeTenABP(更多关于如何使用它的信息,请参见此处)。

下面的代码适用于两者。唯一的区别是包名称(在 Java 8 中是java.time,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是org.threeten.bp),但类和方法名称是相同的。

您可以使用DateTimeFormatter严格模式来做到这一点。这允许日和月中的值为零。其他模式不起作用:默认模式不接受零,宽松模式尝试进行自动转换,因此严格模式是唯一适用于这种情况的模式。

然后您获取各个字段(日和月)并检查它们是否为零。我正在使用该getLong方法(并转换为int),因为该get方法(返回int)检查返回的值是否有效(因此像零这样的值会抛出异常)。

最后,将所有部分连接起来以获得输出:

String valueWithDate = "00092017";
String pattern = "ddMMyyyy";
// create formatter with the pattern and strict mode
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern).withResolverStyle(ResolverStyle.STRICT);
// parse the input
TemporalAccessor parsed = fmt.parse(valueWithDate);

// get day from the parsed object
int day = (int) parsed.getLong(ChronoField.DAY_OF_MONTH);
if (day == 0) {
    day = 1;
}
// get month from the parsed object
int month = (int) parsed.getLong(ChronoField.MONTH_OF_YEAR);
if (month == 0) {
    month = 1;
}
// get year from the parsed object
int year = (int) parsed.getLong(ChronoField.YEAR_OF_ERA);

// the final value will have the same pattern? if so, just use the same formatter
String value = fmt.format(LocalDate.of(year, month, day));
System.out.println(value); // 01092017
Run Code Online (Sandbox Code Playgroud)

因此,对于输入00092017和模式ddMMyyyy,上面的代码将打印:

01092017


正如@MenoHochschild's comment所建议的,您还可以使用该parseUnresolved方法,该方法不验证值,因此它允许日和月为零(并且您不需要将格式化程序设置为严格模式)。

此方法还需要一个java.text.ParsePosition, 用于检查解析错误(因为它不会像该parse方法那样抛出异常):

// create formatter, no need of strict mode
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern);
// parse
ParsePosition pos = new ParsePosition(0);
TemporalAccessor parsed = fmt.parseUnresolved(valueWithDate, pos);
// check errors
if (pos.getErrorIndex() >= 0) {
    // error in parsing (getErrorIndex() returns the index where the error occurred)
}
// rest of the code is the same
Run Code Online (Sandbox Code Playgroud)

正如@OleV.V. 的评论所建议的,您还可以使用以下命令检查整个输入是否未解析:

if(pos.getIndex() < valueWithDate.length()) {
    // the input String wasn't fully parsed
}
Run Code Online (Sandbox Code Playgroud)

我假设最终值将具有与输入中使用的相同格式(传递给方法的相同模式)。

但是,如果您想要其他格式的值,只需创建另一个具有不同模式的格式化程序:

// output in another format
DateTimeFormatter output = DateTimeFormatter.ofPattern("MMddyyyy");
String value = output.format(LocalDate.of(year, month, day));
System.out.println(value); // 09012017
Run Code Online (Sandbox Code Playgroud)