tl;博士
以 MM-dd 格式解析字符串……在当年
MonthDay // Represent a month-day as such, in a class designed for that purpose.
.parse ( // By default parses strings in standard ISO 8601 format.
"--" + "02-29" // Prepending a double-hyphen to make this input comply with ISO 8601.
) // Returns a `MonthDay` object.
.atYear( // Get the date of this month-day in a specified year.
Year.now( ZoneId.of( "Asia/Tokyo" ) ).getValue() // Getting current year requires a time zone.
) // Returns a `LocalDate` object, a year-month-day without time zone and without time-of-day.
看到这个code run live at IdeOne.com。
2019-02-28
java.time
现代解决方案使用 Java 8 及更高版本中内置的行业领先的 java.time 类,并具有可用于 Java 6 和 7 以及早期 Android 的后向端口。
MonthDay
以适当命名的MonthDay 类表示月份。
ISO 8601 中定义的月日标准格式是--MM-DD,其中第一个破折号是年份的占位符。 java.time 类中默认使用 ISO 8601 格式来解析/生成字符串。
您的输入几乎符合要求。您可以使用 DateTimeFormatter 对象定义格式化模式。但我只会在输入前加上--。
String input = "02-29" ;
String inputModified = "--" + input ;
然后默认解析。
MonthDay md = MonthDay.parse( inputModified ) ;
看到这个code run live at IdeOne.com。
md.toString(): --02-29
闰年
请注意,您的leap year 问题消失了。通过使用真正代表月份和日期而不是时刻的适当类型,我们不必担心闰年。
要获取本月的日期,只需调用MonthDay::atYear 以获取LocalDate 对象。通过年号。
LocalDate leapYear2012 = md.atYear( 2012 ) ;
leapYear2012.toString(): 2012-02-29
当年
在当年获得一个日期可能会让您感到惊讶。请注意,获取当前年份需要获取当前日期。获取当前日期需要时区。
时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜过后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。
如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。如果您想使用 JVM 当前的默认时区,请通过调用 ZoneId.systemDefault() 明确您的意图。如果关键,请与您的用户确认该区域。
以Continent/Region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/Auckland。切勿使用 2-4 个字母的缩写,例如 EST 或 IST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
在我们的例子中,我们只关心年份。所以我们可以使用Year 类而不是LocalDate。但与时区相同的想法。如果当前时刻恰好是在新年前夜/新年前夜切换,那么全球各地的年份会因时区而异。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
Year y = Year.now( z ) ;
LocalDate currentYear = md.atYear( y.getValue() ) ;
currentYear.toString(): 2019-02-28
请注意,上述结果中的闰年是自动处理的。 2019年没有2月29日,所以java.time调整为28日。
解析为LocalDate
或者,您可以直接解析为LocalDate。您需要使用 DateTimeFormatterBuilder 类来构建默认为特定年份的 DateTimeFormatter。
类似这样的:
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
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?