SimpleDateFormat中的可选部分

tra*_*ard 40 java datetime localization simpledateformat

我正在读日期字符串,可能有或没有时区调整:yyyyMMddHHmmsszyyyyMMddHHmmss.当一个字符串缺少一个区域时,我将其视为GMT.我没有看到任何方式在a中创建可选部分SimpleDateFormat,但也许我错过了一些东西.有没有办法用a做这个SimpleDateFormat,或者我应该写一个新的具体DateFormat来处理这个?

Bre*_*yan 54

JSR-310已经与Java 8一起提供,它为解析时间值提供了增强的支持,其中组件现在可以是可选的.您不仅可以将区域设为可选区域,还可以使时间组件可选,并为给定字符串返回正确的时间单位.

请考虑以下测试用例.

public class DateFormatTest {

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
            "yyyy-MM-dd[[ ]['T']HH:mm[:ss][XXX]]");

    private TemporalAccessor parse(String v) {
        return formatter.parseBest(v,
                                   ZonedDateTime::from,
                                   LocalDateTime::from,
                                   LocalDate::from);
    }

    @Test public void testDateTime1() {
        assertEquals(LocalDateTime.of(2014, 9, 23, 14, 20, 59),
                     parse("2014-09-23T14:20:59"));
    }

    @Test public void testDateTime2() {
        assertEquals(LocalDateTime.of(2014, 9, 23, 14, 20),
                     parse("2014-09-23 14:20"));
    }

    @Test public void testDateOnly() {
        assertEquals(LocalDate.of(2014, 9, 23), parse("2014-09-23"));
    }

    @Test public void testZonedDateTime() {
        assertEquals(ZonedDateTime.of(2014, 9, 23, 14, 20, 59, 0,
                                      ZoneOffset.ofHoursMinutes(10, 30)),
                     parse("2014-09-23T14:20:59+10:30"));
    }

}
Run Code Online (Sandbox Code Playgroud)

这里的DateTimeFormatter模式"yyyy-MM-dd[[ ]['T']HH:mm[:ss][XXX]]"允许在方括号内的可选项也可以嵌套.模式也可以从DateTimeFormatterBuilder构造,上面的模式在这里演示:

private final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .append(DateTimeFormatter.ISO_LOCAL_DATE)
        .optionalStart()
        .optionalStart()
        .appendLiteral(' ')
        .optionalEnd()
        .optionalStart()
        .appendLiteral('T')
        .optionalEnd()
        .appendOptional(DateTimeFormatter.ISO_TIME)
        .toFormatter();
Run Code Online (Sandbox Code Playgroud)

这将转换为如下所示的表达式:

yyyy-MM-dd[[' ']['T']HH:mm[':'ss[.SSS]]].
Run Code Online (Sandbox Code Playgroud)

可选值可以嵌套,如果仍然打开,也会在结尾处自动关闭.但请注意,无法在可选部件上提供异或,因此上述格式实际上会很好地解析以下值:

2018-03-08 T11:12
Run Code Online (Sandbox Code Playgroud)

请注意我们可以将现有格式化程序作为当前格式的一部分重用的非常简洁的功能.

  • 不,多个选项是正确的,它相当于`yyyy-MM-dd[[' ']['T']HH:mm[':'ss[.SSS]]]`。可选值可以嵌套,如果仍然打开,它们也会在最后自动关闭。 (2认同)

tbr*_*aun 32

我知道这是一个老帖子,但只是为了记录......

Apache DateUtils类可以帮助您.

String[] acceptedFormats = {"dd/MM/yyyy","dd/MM/yyyy HH:mm","dd/MM/yyyy HH:mm:ss"};
Date date1 = DateUtils.parseDate("12/07/2012", acceptedFormats);
Date date2 = DateUtils.parseDate("12/07/2012 23:59:59", acceptedFormats);
Run Code Online (Sandbox Code Playgroud)

链接到Maven存储库中的Apache Commons Lang库,您可能想查看最新版本:http:
//mvnrepository.com/artifact/org.apache.commons/commons-lang3

Maven v3.4

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

Gradle v3.4

'org.apache.commons:commons-lang3:3.4'
Run Code Online (Sandbox Code Playgroud)

  • @Diederik,你能详细说明吗?你的格式有时区吗?行为是否记录在案?这是一个错误吗?如果是这样,你是否提交了错误报告? (2认同)

Pet*_*rey 21

我会创建两个SimpleDateFormat,一个带有时区,一个没有.您可以查看String的长度以确定要使用的字符串.


听起来你需要一个委托给两个不同SDF的DateFormat.

DateFormat df = new DateFormat() {
    static final String FORMAT1 = "yyyyMMddHHmmss";
    static final String FORMAT2 = "yyyyMMddHHmmssz";
    final SimpleDateFormat sdf1 = new SimpleDateFormat(FORMAT1);
    final SimpleDateFormat sdf2 = new SimpleDateFormat(FORMAT2);
    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Date parse(String source, ParsePosition pos) {
        if (source.length() - pos.getIndex() == FORMAT1.length())
            return sdf1.parse(source, pos);
        return sdf2.parse(source, pos);
    }
};
System.out.println(df.parse("20110102030405"));
System.out.println(df.parse("20110102030405PST"));
Run Code Online (Sandbox Code Playgroud)