簡體   English   中英

解析 MM/DD/YY 格式的日期並將其調整為當前/上個世紀的最佳方法是什么?

[英]What is the best way to parse a date in MM/DD/YY format and adjust it to the current / previous century?

我們的一位客戶希望能夠輸入年份部分只有 2 位數字的日期。 日期將是過去的日期,因此如果 2 位數年份晚於當前年份,我們希望它適用於上個世紀,但如果 2 位數年份等於或小於當前年份,則它適用於當前世紀。

截至今天 10/30/2008

01/01/01 = 01/01/2001

01/01/09 = 01/01/1909

這是一個奇怪的要求,我解決了這個問題,我只是不喜歡我的解決方案。 感覺有更好的方法可以做到這一點。

謝謝您的幫助。

public static String stupidDate(String dateString)
{
    String twoDigitYear = StringUtils.right(dateString, 2);
    String newDate = StringUtils.left(dateString, dateString.length() - 2);
    int year = NumberUtils.toInt(twoDigitYear);
    Calendar c = GregorianCalendar.getInstance();
    int centuryInt = c.get(Calendar.YEAR) - year;
    newDate = newDate + StringUtils.left(Integer.toString(centuryInt), 2) + twoDigitYear;
    return newDate;
}

Groovy腳本(很容易引入java)演示@bobince關於SimpleDateFormat的觀點。

import java.text.SimpleDateFormat

SimpleDateFormat sdf = new SimpleDateFormat('MM/dd/yy')
SimpleDateFormat fmt = new SimpleDateFormat('yyyy-MM-dd')

Calendar cal = Calendar.getInstance()
cal.add(Calendar.YEAR, -100)
sdf.set2DigitYearStart(cal.getTime())

dates = ['01/01/01', '10/30/08','01/01/09']
dates.each {String d ->
  println fmt.format(sdf.parse(d))
}

產量

2001-01-01
2008-10-30
1909-01-01

SimpleDateFormat已經為您使用兩個字母的“yy”格式進行了兩位數的年份解析。 (顯然它仍然允許四位數。)

默認情況下,它使用now-80→now + 20,因此它與你提出的規則不完全相同,但它是合理的和標准化的(至少在Java世界中),並且如果你願意,可以使用set2DigitYearStart()覆蓋它。

DateFormat informat= new SimpleDateFormat("MM/dd/yy");
DateFormat outformat= new SimpleDateFormat("MM/dd/yyyy");
return outformat.format(informat.parse(dateString));

從長遠來看,嘗試遷移到ISO8601日期格式(yyyy-MM-dd),因為MM / dd / yy大約是最糟糕的日期格式,並且最終會導致問題。

這個怎么樣:

public static String anEasierStupidDateWithNoStringParsing(String dateString) {
    DateFormat df = new SimpleDateFormat("MM/dd/yyyy");

    //handling ParseExceptions is an exercise left to the reader!
    Date date = df.parse(dateString);
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);

    Calendar now = Calendar.getInstance();
    if (cal.after(now)) {
        cal.add(Calendar.YEAR, -100);
    }

    return cal;
}

換句話說,如果SimpleDateFormat( 它有自己的解釋年份字符串的規則 )返回當前日期之后的日期,讓SimpleDateFormat解析String並將年份調整為上個世紀。

這樣可以保證返回的所有日期都是過去的。 但是,它沒有說明在上個世紀之前可能被解析的任何日期 - 例如,格式為MM/dd/yyyy ,日期字符串如“01/11/12”解析為公元12年1月11日

如果Joda Time是一個選項:

String inputDate = "01/01/08";
// assuming U.S. style date, since it's not clear from your original question
DateTimeFormatter parser = DateTimeFormat.forPattern("MM/dd/yy");
DateTime dateTime = parser.parseDateTime(inputDate);
// if after current time
if (dateTime.isAfter(new DateTime())) {
    dateTime = dateTime.minus(Years.ONE);
}

return dateTime.toString("MM/dd/yyyy");

我知道Joda Time不是Java SE的一部分,正如我在另一個帖子中所說的那樣,當有一個Java庫做同樣的事情時,我通常不會寬恕使用第三方庫。 然而,正在開發Joda Time的人也在領導JSR310--日期和時間API,它將進入Java 7.所以我Joda Time基本上將在未來的Java版本中。

接受的答案使用遺留日期時間 API,這是 2008 年提出問題時的正確做法。 2014 年 3 月, java.time API 取代了容易出錯的遺留日期時間 API 從那時起,強烈建議使用這個現代日期時間 API。

java.time API

  1. 您可以在DateTimeFormatterBuilder#optionalStartDateTimeFormatterBuilder#optionalEnd之間放置可選模式,並創建一個格式化程序,它可以解析具有四位數年份或兩位數年份的日期字符串。
  2. 使用DateTimeFormatterBuilder#appendValueReduced ,您可以根據需要指定年份的基值。

演示

import java.time.LocalDate;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter parser = new DateTimeFormatterBuilder()
                .appendPattern("M/d/")
                .optionalStart()
                .appendPattern("uuuu")
                .optionalEnd()
                .optionalStart()
                .appendValueReduced(ChronoField.YEAR, 2, 2, Year.now().minusYears(100).getValue())
                .optionalEnd()
                .toFormatter(Locale.ENGLISH);

        // Test
        Stream.of(
                "1/2/2022",
                "01/2/2022",
                "1/02/2022",
                "01/02/2022",
                "1/2/22",
                "1/2/21",
                "1/2/20",
                "1/2/23",
                "1/2/24"
            )
            .map(s -> LocalDate.parse(s, parser))
            .forEach(System.out::println);
    }
}

Output :

2022-01-02
2022-01-02
2022-01-02
2022-01-02
1922-01-02
2021-01-02
2020-01-02
1923-01-02
1924-01-02

請注意,年份大於當前年份的兩位數的日期將被解析為具有上個世紀的LocalDate


如何從舊版切換到現代日期時間 API?

您可以在 java-util-date 實例上使用Date#toInstant從舊日期時間切換到現代日期時間 API。 一旦你有了一個Instant ,你就可以很容易地獲得其他日期時間類型java.time API。一個Instant代表一個時刻並且獨立於時區,即它代表一個 UTC 日期時間(通常顯示為Z代表祖魯時間並且ZoneOffset+00:00 )。

演示

public class Main {
    public static void main(String[] args) {
        Date date = new Date();
        Instant instant = date.toInstant();
        System.out.println(instant);

        ZonedDateTime zdt = instant.atZone(ZoneId.of("Asia/Kolkata"));
        System.out.println(zdt);

        OffsetDateTime odt = instant.atOffset(ZoneOffset.of("+05:30"));
        System.out.println(odt);
        // Alternatively, using time-zone
        odt = instant.atZone(ZoneId.of("Asia/Kolkata")).toOffsetDateTime();
        System.out.println(odt);

        LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.of("Asia/Kolkata"));
        System.out.println(ldt);
        // Alternatively,
        ldt = instant.atZone(ZoneId.of("Asia/Kolkata")).toLocalDateTime();
        System.out.println(ldt);
    }
}

Output :

2022-11-20T20:32:42.823Z
2022-11-21T02:02:42.823+05:30[Asia/Kolkata]
2022-11-21T02:02:42.823+05:30
2022-11-21T02:02:42.823+05:30
2022-11-21T02:02:42.823
2022-11-21T02:02:42.823

Trail:Date Time了解有關現代日期時間 API 的更多信息。

Date deliverDate = new SimpleDateFormat("MM/dd/yy").parse(deliverDateString);
String dateString2 = new SimpleDateFormat("yyyy-MM-dd").format(deliverDate);

為我工作

喬達時代的樞紐年

優秀的Joda-Time 2.5庫包含此功能。 無需自己編寫任何代碼。 只需在DateTimeFormatter上調用withPivotYear() 有關如何使用它的示例,請參閱該鏈接文檔。

最好的方法是在Java中使用Joda Time API來表示日期和時間。

暫無
暫無

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

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