如何使用SimpleDateFormat以多种格式解析日期

Der*_*rek 49 java datetime parsing simpledateformat

我正在尝试解析文档中出现的一些日期.看起来用户已经以类似但不精确的格式输入这些日期.

以下是格式:

9/09
9/2009
09/2009
9/1/2009
9-1-2009 
Run Code Online (Sandbox Code Playgroud)

尝试解析所有这些问题的最佳方法是什么?这些似乎是最常见的,但我想是什么让我感到高兴的是,如果我有一个"M/yyyy"模式,那么总是会在"MM/yyyy"之前捕获我是否必须设置我的try/catch块嵌套在限制最少的限制性方式?似乎肯定会采取大量代码重复来实现这一目标.

Mat*_*all 76

您需要SimpleDateFormat为每个不同的模式使用不同的对象.也就是说,你不需要那么多不同的,多亏了这个:

数字:对于格式化,模式字母的数量是最小位数,较短的数字是零填充到此数量.对于解析,除非需要分隔两个相邻字段,否则将忽略模式字母的数量.

所以,你需要这些格式:

  • "M/y"(覆盖9/09,9/200909/2009)
  • "M/d/y"(涵盖9/1/2009)
  • "M-d-y"(涵盖9-1-2009)

所以,我的建议是编写一个类似于这样的方法(未经测试):

// ...
List<String> formatStrings = Arrays.asList("M/y", "M/d/y", "M-d-y");
// ...

Date tryParse(String dateString)
{
    for (String formatString : formatStrings)
    {
        try
        {
            return new SimpleDateFormat(formatString).parse(dateString);
        }
        catch (ParseException e) {}
    }

    return null;
}
Run Code Online (Sandbox Code Playgroud)

  • 这里的许多答案都提供了某种形式的解决方案,但不幸的是它不起作用。如果正在解析的字符串与格式 #3 匹配,则 SimpleDateFormat 很可能会成功解析格式 #1,但您会得到错误的日期。 (2认同)

小智 20

那么只定义多个模式呢?它们可能来自包含已知模式的配置文件,硬编码如下:

List<SimpleDateFormat> knownPatterns = new ArrayList<SimpleDateFormat>();
knownPatterns.add(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"));
knownPatterns.add(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm.ss'Z'"));
knownPatterns.add(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"));
knownPatterns.add(new SimpleDateFormat("yyyy-MM-dd' 'HH:mm:ss"));
knownPatterns.add(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"));

for (SimpleDateFormat pattern : knownPatterns) {
    try {
        // Take a try
        return new Date(pattern.parse(candidate).getTime());

    } catch (ParseException pe) {
        // Loop on
    }
}
System.err.println("No known Date format found: " + candidate);
return null;
Run Code Online (Sandbox Code Playgroud)


Chr*_*isR 15

马特上面的方法很好,但请注意,如果你用它来区分格式y/M/d和日期,你会遇到问题d/M/y.例如,初始化的格式化程序y/M/d将接受类似的日期,01/01/2009并返回一个显然不是您想要的日期.我把问题修复如下,但我的时间有限,我对解决方案不满意有两个主要原因:

  1. 它违反了Josh Bloch的一项准则,特别是"不使用例外处理程序流程".
  2. getDateFormat()如果您需要它来处理许多其他日期格式,我可以看到该方法变得有点噩梦.

如果我必须创建一些可以处理大量不同日期格式并且需要高性能的东西,那么我想我会使用创建枚举的方法将每个不同的日期正则表达式链接到它的格式.然后使用MyEnum.values()循环遍历枚举并测试if(myEnum.getPattern().matches(date))而不是捕获dateformatexception.

Anway,如上所述,以下内容可以处理格式的日期'y/M/d' 'y-M-d' 'y M d' 'd/M/y' 'd-M-y' 'd M y'以及包含时间格式的格式的所有其他变体:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtil {
    private static final String[] timeFormats = {"HH:mm:ss","HH:mm"};
    private static final String[] dateSeparators = {"/","-"," "};

    private static final String DMY_FORMAT = "dd{sep}MM{sep}yyyy";
    private static final String YMD_FORMAT = "yyyy{sep}MM{sep}dd";

    private static final String ymd_template = "\\d{4}{sep}\\d{2}{sep}\\d{2}.*";
    private static final String dmy_template = "\\d{2}{sep}\\d{2}{sep}\\d{4}.*";

    public static Date stringToDate(String input){
    Date date = null;
    String dateFormat = getDateFormat(input);
    if(dateFormat == null){
        throw new IllegalArgumentException("Date is not in an accepted format " + input);
    }

    for(String sep : dateSeparators){
        String actualDateFormat = patternForSeparator(dateFormat, sep);
        //try first with the time
        for(String time : timeFormats){
        date = tryParse(input,actualDateFormat + " " + time);
        if(date != null){
            return date;
        }
        }
        //didn't work, try without the time formats
        date = tryParse(input,actualDateFormat);
        if(date != null){
        return date;
        }
    }

    return date;
    }

    private static String getDateFormat(String date){
    for(String sep : dateSeparators){
        String ymdPattern = patternForSeparator(ymd_template, sep);
        String dmyPattern = patternForSeparator(dmy_template, sep);
        if(date.matches(ymdPattern)){
        return YMD_FORMAT;
        }
        if(date.matches(dmyPattern)){
        return DMY_FORMAT;
        }
    }
    return null;
    }

    private static String patternForSeparator(String template, String sep){
    return template.replace("{sep}", sep);
    }

    private static Date tryParse(String input, String pattern){
    try{
        return new SimpleDateFormat(pattern).parse(input);
    }
    catch (ParseException e) {}
    return null;
    }


}
Run Code Online (Sandbox Code Playgroud)


小智 10

如果在 Java 1.8 中工作,您可以利用 DateTimeFormatterBuilder

public static boolean isTimeStampValid(String inputString)
{
    DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ofPattern("" + "[yyyy-MM-dd'T'HH:mm:ss.SSSZ]" + "[yyyy-MM-dd]"));

    DateTimeFormatter dateTimeFormatter = dateTimeFormatterBuilder.toFormatter();

    try {
        dateTimeFormatter.parse(inputString);
        return true;
    } catch (DateTimeParseException e) {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅帖子:Java 8 Date 等效于具有多种解析器格式的 Joda 的 DateTimeFormatterBuilder?


pra*_*ash 9

最佳且简单的 Java 8 答案 (来自/sf/answers/4168240331/

final DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"))
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);
Run Code Online (Sandbox Code Playgroud)

  • 这对我有用,但看起来添加格式化程序的顺序在某种程度上很重要。我需要处理 `yyyy-MM-dd HH:mm:ss.SSS` 和 `yyyy-MM-dd HH:mm:ss.S` 但如果我首先指定带有一毫秒字符的模式,则会失败。如果我首先放置包含三毫秒字符的模式,则两种格式都会正确处理。 (2认同)

SAN*_*NN3 8

在Apache commons lang,DateUtils类中我们有一个名为parseDate的方法.我们可以用它来解析日期.

另一个库Joda-time也有解析日期的方法.


Vin*_*ala 6

这是完整的示例(带有 main 方法),可以将其作为实用程序类添加到您的项目中。下面的方法支持SimpleDateFormate API 中提到的所有格式。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.lang.time.DateUtils;

public class DateUtility {

    public static Date parseDate(String inputDate) {

        Date outputDate = null;
        String[] possibleDateFormats =
              {
                    "yyyy.MM.dd G 'at' HH:mm:ss z",
                    "EEE, MMM d, ''yy",
                    "h:mm a",
                    "hh 'o''clock' a, zzzz",
                    "K:mm a, z",
                    "yyyyy.MMMMM.dd GGG hh:mm aaa",
                    "EEE, d MMM yyyy HH:mm:ss Z",
                    "yyMMddHHmmssZ",
                    "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
                    "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
                    "YYYY-'W'ww-u",
                    "EEE, dd MMM yyyy HH:mm:ss z", 
                    "EEE, dd MMM yyyy HH:mm zzzz",
                    "yyyy-MM-dd'T'HH:mm:ssZ",
                    "yyyy-MM-dd'T'HH:mm:ss.SSSzzzz", 
                    "yyyy-MM-dd'T'HH:mm:sszzzz",
                    "yyyy-MM-dd'T'HH:mm:ss z",
                    "yyyy-MM-dd'T'HH:mm:ssz", 
                    "yyyy-MM-dd'T'HH:mm:ss",
                    "yyyy-MM-dd'T'HHmmss.SSSz",
                    "yyyy-MM-dd",
                    "yyyyMMdd",
                    "dd/MM/yy",
                    "dd/MM/yyyy"
              };

        try {

            outputDate = DateUtils.parseDate(inputDate, possibleDateFormats);
            System.out.println("inputDate ==> " + inputDate + ", outputDate ==> " + outputDate);

        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return outputDate;

    }

    public static String formatDate(Date date, String requiredDateFormat) {
        SimpleDateFormat df = new SimpleDateFormat(requiredDateFormat);
        String outputDateFormatted = df.format(date);
        return outputDateFormatted;
    }

    public static void main(String[] args) {

        DateUtility.parseDate("20181118");
        DateUtility.parseDate("2018-11-18");
        DateUtility.parseDate("18/11/18");
        DateUtility.parseDate("18/11/2018");
        DateUtility.parseDate("2018.11.18 AD at 12:08:56 PDT");
        System.out.println("");
        DateUtility.parseDate("Wed, Nov 18, '18");
        DateUtility.parseDate("12:08 PM");
        DateUtility.parseDate("12 o'clock PM, Pacific Daylight Time");
        DateUtility.parseDate("0:08 PM, PDT");
        DateUtility.parseDate("02018.Nov.18 AD 12:08 PM");
        System.out.println("");
        DateUtility.parseDate("Wed, 18 Nov 2018 12:08:56 -0700");
        DateUtility.parseDate("181118120856-0700");
        DateUtility.parseDate("2018-11-18T12:08:56.235-0700");
        DateUtility.parseDate("2018-11-18T12:08:56.235-07:00");
        DateUtility.parseDate("2018-W27-3");
    }

}
Run Code Online (Sandbox Code Playgroud)


loc*_*cto 5

该解决方案在引发异常之前检查所有可能的格式。如果您尝试测试多种日期格式,此解决方案会更方便。

Date extractTimestampInput(String strDate){
    final List<String> dateFormats = Arrays.asList("yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd");    

    for(String format: dateFormats){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try{
            return sdf.parse(strDate);
        } catch (ParseException e) {
             //intentionally empty
        }
    }
        throw new IllegalArgumentException("Invalid input for date. Given '"+strDate+"', expecting format yyyy-MM-dd HH:mm:ss.SSS or yyyy-MM-dd.");

}
Run Code Online (Sandbox Code Playgroud)