使用新的日期时间API格式化日期


118

我正在使用新的日期时间API,但是在运行时:

public class Test {         
    public static void main(String[] args){
        String dateFormatted = LocalDate.now()
                                        .format(DateTimeFormatter
                                              .ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println(dateFormatted);
    }
}

它抛出:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
    at java.time.LocalDate.get0(LocalDate.java:680)
    at java.time.LocalDate.getLong(LocalDate.java:659)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2543)
    at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
    at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
    at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
    at java.time.LocalDate.format(LocalDate.java:1685)
    at Test.main(Test.java:23)

查看LocalDate类的源代码时,我看到:

  private int get0(TemporalField field) {
        switch ((ChronoField) field) {
            case DAY_OF_WEEK: return getDayOfWeek().getValue();
            case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
            case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
            case DAY_OF_MONTH: return day;
            case DAY_OF_YEAR: return getDayOfYear();
            case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead");
            case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
            case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
            case MONTH_OF_YEAR: return month;
            case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead");
            case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
            case YEAR: return year;
            case ERA: return (year >= 1 ? 1 : 0);
        }
        throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
    }

如文档中所述:

此方法将根据类文档中描述的简单字母和符号模式创建格式化程序。

并且所有这些字母都已定义

那么为什么DateTimeFormatter.ofPattern不允许我们使用一些图案字母呢?

Answers:


218

LocalDate仅代表一个日期,而不代表DateTime。因此,在格式化a时,“ HH:mm:ss”毫无意义LocalDateLocalDateTime假设您要代表日期和时间,请改用a 。


3
我该如何赞美这个答案,而又反对有一个LocalDate和LocalDateTime对象的事实……
Xials

我只想与LocalTime合作,如何在不遇到此异常的情况下执行格式化java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfWeek
samuel owino

没关系:这有效DateTimeFormatter.ofPattern("HH:mm:ss")
塞缪尔·奥维诺

36

我想在@James_D的正确答案中添加以下详细信息:

背景:大多数日期和时间库(java.util.Calendar在Java中,另请参见.Net-DateTime或Date在JavaScript中或DateTime在Perl中)都是基于通用的通用唯一时态类型的概念(德语中具有诗意的表达“ eierlegende Wollmilchsau”)。在此设计中,不能有不受支持的字段。但是代价却很高:用这样一种不灵活的方法无法充分解决许多时间问题,因为很难为所有时间对象找到一个共同的分母。

JSR-310选择了另一种方法,即允许不同的时间类型,这些时间类型由特定类型的受支持内置字段组成。自然的结果是,并非每种类型都支持所有可能的字段(用户甚至可以定义自己的专用字段)。也可以以编程方式向每个类型的对象询问TemporalAccessor其特定的受支持字段集。对于LocalDate我们发现:

DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

没有HOUR_OF_DAY字段可以解释的问题UnsupportedTemporalTypeException。并且,如果我们查看JSR-310- 模式符号到字段的映射,我们会看到符号H被映射到不受支持的HOUR_OF_DAY:

/** Map of letters to fields. */  
private static final Map<Character, TemporalField> FIELD_MAP = new HashMap<>();
static {
  FIELD_MAP.put('G', ChronoField.ERA);
  FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA);
  FIELD_MAP.put('u', ChronoField.YEAR);
  FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR);
  FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR);
  FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR);
  FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR);
  FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR);
  FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH);
  FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH);
  FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY);
  FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY);
  FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY);
  FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM);
  FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM);
  FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR);
  FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE);
  FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND);
  FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY);
  FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND);
  FIELD_MAP.put('N', ChronoField.NANO_OF_DAY);    
}

此字段映射并不意味着具体类型支持该字段。解析过程分为几个步骤。字段映射只是第一步。然后,第二步将解析为type的原始对象TemporalAccessor。最后,将委托解析为目标类型(此处为LocalDate),然后让其决定是否接受已解析的中间对象中的所有字段值。


4
en.wiktionary.org/wiki/eierlegende_Wollmilchsau(字面意思是“产卵的羊毛-牛奶母猪”)一种多合一的设备或人,仅具有(或声称具有)积极的属性,并且可以(或尝试)做几种专门工具的工作。:-)
特雷弗·罗宾逊

6

对我来说,正确的课程ZonedDateTime包括时间和时区。

LocalDate没有时间信息,所以你得到了UnsupportedTemporalTypeException: Unsupported field: HourOfDay

您可以使用,LocalDateTime但那时没有时区信息,因此,如果尝试访问该时区信息(即使使用预定义的格式程序之一),也会收到一个UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.