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

问题描述 投票:3回答:4

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

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)是leap年,2012-02-29是有效日期,应该成功解析“ 02-29”。

[我发现,当我没有在SimpleDateFormat中指定年份部分时,它将解析为1970年。而1970年不是a年,则“ 02-29”将无法解析。因此,解析日期到1970年并在解析策略后设置当前年份并不完美。

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

PS1:我搜索了此主题,并在此站点中找到许多问题和答案,但是找不到满意的答案。PS2:df.setLenient(false);很重要,因为只有有效的日期字符串才能成功解析。无效的日期字符串,例如“ 01-32”,“ 02-30”等,不应被解析。

提前感谢。

java date calendar date-format
4个回答
2
投票
Date d = df.parse(ds + "-" + year);

0
投票
[如果您需要处理未知格式的输入字符串(不确定年份是否在String上,则可以先尝试使用完整格式来解析Date,然后使用覆盖年份。

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);
}

0
投票
MonthDay .parse ( "--" + "02-29" )

java.time

现代解决方案使用Java 8及更高版本内置的业界领先的java.time类,并为Java 6&7和早期Android提供了反向端口。

MonthDay每月以适当命名的MonthDay类表示。

ISO 8601中定义的月日的标准格式是MonthDay,其中第一个破折号是年份的占位符。默认情况下,

java.time类中使用ISO 8601格式来解析/生成字符串。

您的输入几乎合规。您可以使用--MM-DD对象定义格式设置模式。但是我只需在输入上添加DateTimeFormatter

--

然后默认解析。

String input = "02-29" ;
String inputModified = "--" + input ;

参见此MonthDay md = MonthDay.parse( inputModified ) ;

md.toString():--02-29

Le年

请注意,您的code run live at IdeOne.com问题已消失。通过使用真正代表一个月而不是一瞬间的适当类型,我们不必担心leap年。

要获取该月日的日期,只需调用leap year以获取MonthDay::atYear对象。通过一年数。

MonthDay::atYear

leapYear2012.toString():2012-02-29
本年度

获得当年的日期可能会令您感到意外。请注意,获取当前年份需要获取当前日期。并且获取

当前日期需要一个时区。

时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,在LocalDate中午夜之后的几分钟是新的一天,而在LocalDate leapYear2012 = md.atYear( 2012 ) ; 中仍是“昨天”。

如果未指定时区,则JVM隐式应用其当前的默认时区。该默认值可能在运行时(!)期间为Paris France,因此您的结果可能会有所不同。最好将您的期望/期望时区明确指定为参数。如果要使用JVM的当前默认时区,请致电Montréal Québec来表明您的意图。如果紧急,请与用户确认区域。

change at any moment的格式指定ZoneId.systemDefault(),例如proper time zone nameContinent/RegionAmerica/Montreal。切勿使用2-4个字母的缩写,例如Africa/CasablancaPacific/Auckland,因为它们是真正的时区,不是标准化的,甚至不是唯一的(!)。

EST

就我们而言,我们只关心年份。因此,我们可以使用IST类而不是ZoneId z = ZoneId.of( "America/Montreal" ) ; LocalDate today = LocalDate.now( z ) ; 。但是对于时区也是如此。如果当前时刻恰好是除夕/天转换,那么该年份将在全球各地按时区变化。Year

currentYear.toString():2019-02-28

关于该leap年以上结果的通知会自动处理。 2019年2月29日没有,因此
java.time
调整为28日。

关于java.time


LocalDate框架内置于Java 8及更高版本中。这些类取代了麻烦的旧ZoneId z = ZoneId.of( "Africa/Tunis" ) ; Year y = Year.now( z ) ; LocalDate currentYear = md.atYear( y.getValue() ) ; 日期时间类,例如java.timelegacyjava.util.Date

要了解更多信息,请参见java.util.Date。并在Stack Overflow中搜索许多示例和说明。规格为CalendarCalendar项目现在位于SimpleDateFormat中,建议迁移到SimpleDateFormat类。

您可以直接与数据库交换

java.time

对象。使用兼容Oracle Tutorial或更高版本的JSR 310。不需要字符串,不需要Joda-Time类。

从哪里获取java.time类?

maintenance modejava.timeJDBC driverJDBC 4.2和更高版本-具有捆绑实施的标准Java API的一部分。

    Java 9添加了一些次要功能和修复。

  • [java.sql.*Java SE 8
    • << java.time的大多数功能>在Java SE 9中被反向移植到Java 6和7。
  • Java SE 10
    • java.time
    类的Android捆绑包实现的最新版本。
  • 对于较早的Android(<26),Java SE 11项目改编为Java SE 6(如上所述)。参见Java SE 7
  • © www.soinside.com 2019 - 2024. All rights reserved.