如何简单地解析没有指定年份的日期?

时间:2011-12-15 17:06:30

标签: java groovy

我有一个工具,它似乎给了我日期而没有指定我需要转换的年份,我使用Java来完成任务(实际上是Groovy,但在这种情况下足够接近)。一个示例日期是" 13月12日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")

我对这个脚本的问题是SimpleDateFormat似乎在转换后的1970年没有设置。我可以明确地将它设置为2011年,因为那是当前年份,但是当前年份与设定的日期之间似乎存在一些滞后,因此当新年到来时,此脚本将在该滞后时间出错。我该如何解决这个问题呢?一种解决方案是检查当前年份的日期是否已经过去,然后使用去年,但我希望有一个更简单的解决方案(或说“如果不是最简单的解决方案”)。

5 个答案:

答案 0 :(得分:5)

您可以使用java.util.Calendar获取当前年份,如下例所示。

Calendar.getInstance ().get (Calendar.YEAR);

示例摘录

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

输出

  

2011 13 Dec 12:00:00

     

2010 31 Dec 12:00:00


请注意抛出Exceptions

答案 1 :(得分:5)

现代答案(从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;
}

然后我们可以这样做:

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

今天(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日。

消息:

  • 虽然其他答案在2011年是很好的答案,但课程DateSimpleDateFormatCalendarGregorianCalendar现在已经过时了,所以我建议避免使用它们。现代课程通常更方便程序员,并且带来更少的令人不快的惊喜。
  • 始终给出正确的时区。使用不正确的时区可能会导致测试未来的日期时间不准确,从而有可能导致结果停用1年。
  • 始终提供明确的区域设置。在这种情况下,我将“Dec”用于英语并提供了Locale.ENGLISH
  • 由于您认为可以安全地假设日期在去年之内,我邀请您考虑是否也可以安全地假设它在过去的4,6或8个月内,例如?如果是这样,测试是否是这种情况将为您提供更好的验证:

    if (dateTime.isBefore(now.minusMonths(5))) {
        throw new IllegalArgumentException("Not within the last 5 months: " + stringWithoutYear);
    }
    

答案 2 :(得分:1)

  String date_string = "13 Dec 12:00:00";
  SimpleDateFormat sdf = new SimpleDateFormat("dd MMM HH:mm:ss yyyy");
  Date date = sdf.parse(date_string + " " + Calendar.getInstance ().get(Calendar.YEAR));          
  System.out.println(date);

<强>输出:

Tue Dec 13 12:00:00 IST 2011

答案 3 :(得分:0)

最简单的解决方案是在解析之前将当前年份附加到日期字符串。例如:

def currentYear = new Date()[Calendar.YEAR]
def d = Date.parse("dd MMM HH:mm:ss yyyy", "13 Dec 12:00:00 " + currentYear)
println d
===> Tue Dec 13 12:00:00 MST 2011

答案 4 :(得分:0)

    GregorianCalendar now = new GregorianCalendar();
GregorianCalendar goal= new GregorianCalendar(now.get(Calendar.YEAR), month-1, day);
if (goal.after(now)) {
    goal.add(Calendar.YEAR, -1);
}

目标有你的更正日期。