簡體   English   中英

如何簡單地解析沒有指定年份的日期?

[英]How do I simply parse a date without a year specified?

我有一個工具,它似乎給了我日期,但沒有指定我需要轉換的年份,我正在使用 Java 來完成這項任務(實際上是 Groovy,但在這種情況下足夠接近)。 一個示例日期是“13 Dec 12:00:00”,它應該是指 2011 年 12 月 13 日,因為未指定年份並且它是 2011 年。以下 Groovy 腳本可以解決問題:

import java.text.*
println new SimpleDateFormat("dd MMM HH:mm:ss").parse("13 Dec 12:00:00")

我對這個腳本的問題是 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;
}

然后我們可以這樣做:

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

您可以使用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 年 12 月 13 日 12:00:00

2010 年 12 月 31 日 12:00:00


記住要注意拋出的Exceptions

  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

最簡單的解決方案是在解析之前將當前年份附加到日期字符串。 例如:

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
    GregorianCalendar now = new GregorianCalendar();
GregorianCalendar goal= new GregorianCalendar(now.get(Calendar.YEAR), month-1, day);
if (goal.after(now)) {
    goal.add(Calendar.YEAR, -1);
}

目標有您的更正日期。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM