将日期字符串(MM dd)解析为默认年份中的java日期

将日期字符串(MM dd)解析为默认年份中的java日期,java,date,calendar,date-format,Java,Date,Calendar,Date Format,我想将MM dd格式的字符串解析为java日期。由于未指定年份,解析的日期应为当前年份。应该只解析有效的日期字符串,因此我应该在SimpleDateFormat中使用setLenient(false) public static Date parseDate(String ds) throws ParseException { SimpleDateFormat df = new SimpleDateFormat("MM-dd"); df.setLenient(false);

我想将MM dd格式的字符串解析为java日期。由于未指定年份,解析的日期应为当前年份。应该只解析有效的日期字符串,因此我应该在
SimpleDateFormat
中使用
setLenient(false)

public static Date parseDate(String ds) throws ParseException {
    SimpleDateFormat df = new SimpleDateFormat("MM-dd");
    df.setLenient(false);
    Date d = df.parse(ds);
    Calendar cal = Calendar.getInstance();
    int year = cal.get(Calendar.YEAR);
    cal.setTime(d);
    cal.set(Calendar.YEAR, year);
    return cal.getTime();
}
在我通过论点“02-29”之前,这似乎很有效。今年(2012年)是闰年,2012-02-29是有效日期,“02-29”应已成功解析

我发现当我在
SimpleDateFormat
中没有指定年份部分时,它解析为1970年。1970年不是闰年,“02-29”无法解析。所以,解析到1970年的日期和设置本年度后的解析策略并不完善

用Java解析MM dd格式字符串到日期(日期应设置为当前年份)的最佳方法是什么?

PS1:我搜索了这个话题,在这个网站上找到了很多问题和答案,但是我没有找到满意的答案。 PS2:
df.setLenient(假)很重要,因为只有有效的日期字符串才能成功解析。不应分析无效的日期字符串,如“01-32”、“02-30”等


提前感谢。

这可能会被认为有点不正常,但在解析之前,您可以将年份固定在日期字符串的末尾,如下所示:

ds += "-" + Calendar.getInstance().get(Calendar.YEAR);
SimpleDateFormat df = new SimpleDateFormat("MM-dd-yyyy");
// Parse date as usual
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;
long yearNumber = Year.now( zKolkata ).getValue() ;
DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseDefaulting( ChronoField.YEAR , yearNumber ).appendPattern( "MM-dd").toFormatter() ;
LocalDate ld = LocalDate.parse( "02-28" , formatter ) ;
System.out.println( "ld.toString(): " + ld ) ;

按照代码中的操作从日历中获取年份,将解析格式字符串设置为
MM dd yyyy
,然后执行以下操作

 Date d = df.parse(ds + "-" + year);

如果您知道字符串的格式正确,那么关于追加当前年份的其他答案就足够了

如果您需要处理未知格式的输入字符串(您不确定字符串上是否有年份),可以首先尝试使用完整格式解析日期,然后使用较短的格式替换年份

public static Date parseDate(String ds) throws ParseException {
    SimpleDateFormat fullFormat = new SimpleDateFormat("MM-dd-yyyy");
    fullFormat.setLenient(false);
    try {
      return fullFormat.parse(ds);
    } catch (ParseException e) {}

    // Full format unsuccessful. Attempt short format.
    SimpleDateFormat shortFormat = new SimpleDateFormat("MM-dd");
    shortFormat.setLenient(false);
    Date d = shortFormat.parse(ds);
    Calendar cal = Calendar.getInstance();
    int year = cal.get(Calendar.YEAR);
    cal.setTime(d);
    cal.set(Calendar.YEAR, year);
    return cal.getTime();
}
好处:如果出于某种原因需要一个“包罗万象”解析器,请定义一组非宽松的日期格式,并逐一检查它们。注意顺序很重要;第一个匹配的将返回。如果要设置默认年份,则必须进一步检查输入中是否引用了默认1970年:

public static Date parseDate(String ds) throws ParseException {
  Calendar cal = Calendar.getInstance();
  int currentYear = cal.get(Calendar.YEAR);

  for (DateFormat knownFormat : knownFormats) {
    try {
      Date d = knownFormat.parse(ds);
      cal.setTime(d);

      if (cal.get(Calendar.YEAR) == 1970 && !ds.contains("70")) {
        cal.set(Calendar.YEAR, currentYear);
      }

      return cal.getTime();
    } catch (ParseException e) {}
  }

  throw new ParseException("Unknown date format for String: " + ds);
}
tl;博士 分析当前年度的MM dd格式的字符串

看这个

2019-02-28

java.time 现代解决方案使用业界领先的java.time类,内置于java 8和更高版本中,并为java 6和7以及早期Android提供了一个后端端口

MonthDay
带有日期的月份由适当命名的类表示

ISO 8601中定义的月-日的标准格式是
--MM-DD
,其中第一个破折号是年的占位符。默认情况下,在java.time类中使用ISO 8601格式来解析/生成字符串

您的输入几乎符合要求。您可以使用
DateTimeFormatter
对象定义格式化模式。但我只想在输入中预先添加一个
--

String input = "02-29" ;
String inputModified = "--" + input ;
然后默认情况下解析

MonthDay md = MonthDay.parse( inputModified ) ;
看这个

md.toString():--02-29

闰年 注意,你的问题消失了。通过使用真正代表一个月和一天而不是一个时刻的适当类型,我们不必担心闰年

要获取这个月的日期,只需调用获取
LocalDate
对象。通过一个年号

LocalDate leapYear2012 = md.atYear( 2012 ) ;
leapYear2012.toString():2012-02-29

本年度 在本年度获得一个约会可能会让你感到惊讶。请注意,获取当前年份需要获取当前日期。获取当前日期需要一个时区

时区对于确定日期至关重要。在任何一个特定的时刻,世界各地的日期都因地区而异。例如,中午夜后几分钟是新的一天,而中仍然是“昨天”

如果未指定时区,JVM将隐式应用其当前默认时区。该默认值可能在运行时(!)期间出现,因此您的结果可能会有所不同。最好将所需/预期时区明确指定为参数。如果要使用JVM的当前默认时区,请通过调用
ZoneId.systemDefault()
明确您的意图。如果关键,请与用户确认区域

大陆/地区
的格式指定,例如
美国/蒙特利尔
非洲/卡萨布兰卡
,或
太平洋/奥克兰
。切勿使用2-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

就我们而言,我们只关心年份。因此,我们可以使用该类而不是
LocalDate
。但时区也是如此。如果当前时刻恰好是除夕夜/日转换前后,那么全球各地的年份将因时区而异

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
Year y = Year.now( z ) ;
LocalDate currentYear = md.atYear( y.getValue() ) ;
当前年份.toString():2019-02-28

请注意,在上面的结果中,闰年是自动处理的。2019年没有2月29日,因此java.time调整为28日

解析为
LocalDate
或者,您可以直接解析为
LocalDate
。您需要使用
DateTimeFormatterBuilder
类来构建默认为特定年份的
DateTimeFormatter

大概是这样的:

ds += "-" + Calendar.getInstance().get(Calendar.YEAR);
SimpleDateFormat df = new SimpleDateFormat("MM-dd-yyyy");
// Parse date as usual
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;
long yearNumber = Year.now( zKolkata ).getValue() ;
DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseDefaulting( ChronoField.YEAR , yearNumber ).appendPattern( "MM-dd").toFormatter() ;
LocalDate ld = LocalDate.parse( "02-28" , formatter ) ;
System.out.println( "ld.toString(): " + ld ) ;
但我不建议这样做。使用
MonthDay
对象的方法可以更清楚地了解您的问题、解决方案和意图。另一个好处是:如果你得到了这样的输入,我怀疑你可能需要使用月日,而使用
MonthDay
类你手头有一个对象来完成这项工作


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

该项目现已启动,建议迁移到类