我有一个工具似乎给了我日期而没有指定我需要转换的年份,我正在使用Java来完成任务(实际上是Groovy但在这种情况下足够接近).一个示例日期是"13 Dec 12:00:00",应该引用12/13/2011,因为未指定年份,它是2011.以下Groovy脚本可以解决这个问题:
import java.text.*
println new SimpleDateFormat("dd MMM HH:mm:ss").parse("13 Dec 12:00:00")
Run Code Online (Sandbox Code Playgroud)
我对这个脚本的问题是SimpleDateFormat似乎在转换后的1970年没有设置.我可以明确地将它设置为2011年,因为那是当前年份,但是当前年份与设定的日期之间似乎存在一些滞后,因此当新年到来时,此脚本将在该滞后时间出错.我该如何解决这个问题呢?一种解决方案是检查当前年份的日期是否已经过去,然后使用去年,但我希望有一个更简单的解决方案(或者说最简单的解决方案).
现代答案(从2014年开始有效):我首先声明一个辅助方法:
private static LocalDateTime parseWithDefaultYear(String stringWithoutYear, int defaultYear) {
DateTimeFormatter parseFormatter = new DateTimeFormatterBuilder()
.appendPattern("dd MMM HH:mm:ss")
.parseDefaulting(ChronoField.YEAR, defaultYear)
.toFormatter(Locale.ENGLISH);
LocalDateTime dateTime = LocalDateTime.parse(stringWithoutYear, parseFormatter);
return dateTime;
}
Run Code Online (Sandbox Code Playgroud)
然后我们可以这样做:
ZoneId zone = ZoneId.of("America/Argentina/Jujuy");
String stringWithoutYear = "13 Dec 12:00:00";
LocalDateTime now = LocalDateTime.now(zone);
int defaultYear = now.getYear();
LocalDateTime dateTime = parseWithDefaultYear(stringWithoutYear, defaultYear);
if (dateTime.isAfter(now)) { // in the future
defaultYear--;
dateTime = parseWithDefaultYear(stringWithoutYear, defaultYear);
}
System.out.println(dateTime);
Run Code Online (Sandbox Code Playgroud)
今天(2018年6月)运行时打印:
2017-12-13T12:00
你可能会问为什么我想用新的格式化器再次解析,以防第一次尝试在将来给出一个日期.减去1年不是更简单吗?虽然java.time肯定对此有很好的支持,但我选择了第二次解析来处理闰年2月29日的角落情况.想象一下,代码是在2021年的前几个月运行的,字符串是29 Feb 12:00:00.由于2021年不是闰年,Java将选择2月28日,即该月的最后一天.减去1年将给2020年2月28日,这是不正确的,因为2020年是闰年.相反,我对2020年作为默认年份的新解析给出了正确的2020年2月29日.
消息:
Date,SimpleDateFormat,Calendar和GregorianCalendar现在早已过时的,所以我建议避免它们.现代课程通常对程序员更友好,并且带来更少的令人不快的惊喜.Locale.ENGLISH.由于您认为可以安全地假设日期在去年之内,我邀请您考虑是否也可以安全地假设它在过去的4,6或8个月内,例如?如果是这样,测试是否是这种情况将为您提供更好的验证:
if (dateTime.isBefore(now.minusMonths(5))) {
throw new IllegalArgumentException("Not within the last 5 months: " + stringWithoutYear);
}
Run Code Online (Sandbox Code Playgroud)您可以使用java.util.Calendar获取当前年份,如下例所示.
Calendar.getInstance ().get (Calendar.YEAR);
Run Code Online (Sandbox Code Playgroud)
示例代码段
OP详细阐述了他的问题,因此这个片段已被重写以符合他的需要.
public static String fixDate (String data) throws Exception {
SimpleDateFormat dateInputFormat = new SimpleDateFormat("dd MMM HH:mm:ss");
SimpleDateFormat dateOutputFormat = new SimpleDateFormat("yyyy dd MMM HH:mm:ss");
Calendar currentCal = Calendar.getInstance ();
Calendar parsedCal = Calendar.getInstance ();
int CAL_YEAR = Calendar.YEAR;
parsedCal.setTime (dateInputFormat.parse (data));
parsedCal.set (CAL_YEAR, currentCal.get (CAL_YEAR));
if (parsedCal.after (currentCal))
parsedCal.set (CAL_YEAR, parsedCal.get (CAL_YEAR) - 1);
// Date parsedDate = parsedCal.getTime ();
return dateOutputFormat.format (parsedCal.getTime ());
}
public static void main (String[] args) throws Exception {
System.out.println (fixDate ("13 Dec 12:00:00"));
System.out.println (fixDate ("31 Dec 12:00:00"));
}
Run Code Online (Sandbox Code Playgroud)
产量
2011年12月13日12:00:00
2010年12月31日12:00:00
记得要注意抛出Exceptions!