【问题标题】:Java date format for 00 days/months00 天/月的 Java 日期格式
【发布时间】:2017-09-05 10:16:22
【问题描述】:

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

例子:

String value = "03082017";

然后我做:

    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;

这适用于示例String

现在我有了这个字符串:

String value = "00092017" //ddMMyyyy 

然后我的代码将00 day 转换为01

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

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

所以代码的模式是ddMMyyyy,但值是03092017 (MMddyyyy)

String day = "03";
.....

我的代码:

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
}

【问题讨论】:

  • 为什么不直接使用日期格式化程序?
  • 如何检查模式?任何小于或等于 12 的日期和月份都是有效的,但可能是错误的方式......
  • 除非这是出于教育目的:不要不要重新发明轮子。 Java 有很多选项可以进行日期解析......当你限制自己使用 Java8 添加的东西时 - 你会得到很多非常有用的东西。
  • 这听起来不可能。您如何确定 11032017 是 3 月 11 日还是 11 月 3 日?在 11002017 中,如何判断是缺日还是缺月?
  • 也许更好理解:我的方法得到 2 个字符串:值和模式,当值为 00082017 //ddMMyyyy 并且模式是 ddMMyyyy 现在在我的方法中我有 3 个字符串:日 = 月 = 和年 = 现在我将填写字符串日 = 00 月 = 08 年 = 2017 我该怎么做?我在第一篇文章中的示例有效,但是当我得到值 09002017 和模式 MMddyyyy 那么它不起作用

标签: java date zero date-parsing dayofmonth


【解决方案1】:

如果您使用的是 Java 8,则可以使用 new java.time API。更简单,less bugged and less error-prone than the old APIs

如果您使用的是 Java ,则可以使用 ThreeTen Backport,它是 Java 8 新日期/时间类的一个很好的向后移植。对于Android,您还需要ThreeTenABP(更多关于如何使用它here)。

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

您可以使用带有严格模式的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

因此,对于输入 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

正如@OleV.V.'s comment 建议的那样,您还可以检查整个输入是否未被解析,使用:

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

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

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

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

【讨论】:

  • 在严格模式下允许零日或月似乎不合逻辑。真的很纳闷。如需更优雅的方式,请参阅此example
  • @MenoHochschild 确实,我也认为 strict 应该意味着 我不接受奇怪的值,但它确实有效。也许是错误的名字选择?
  • 在Java-8的范围内,我建议你考虑替代parser.parseUnresolved("00092017", new ParsePosition(0)),因为它似乎不依赖于解析样式的非理性行为。
  • @MenoHochschild 太好了,parseUnresolved 无论解析方式如何都能正常工作。我已经更新了答案,非常感谢!
  • 感谢您的编辑。我认为在大多数用例中,在parseUnresolved() 之后,我想检查解析位置是否表明整个字符串已被解析。这将增强输入验证。
猜你喜欢
  • 2023-01-13
  • 2015-02-03
  • 1970-01-01
  • 2014-04-26
  • 2020-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多