繁体   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