簡體   English   中英

使用新的日期時間格式化日期 API

[英]Format a date using the new date time API

我正在使用新的日期時間 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 class 的源代碼時,我看到:

  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);
    }

如文檔中所述:

此方法將根據 class 文檔中描述的簡單字母和符號模式創建格式化程序。

並且所有這些字母都被定義了。

那么為什么DateTimeFormatter.ofPattern不允許我們使用一些模式字母呢?

LocalDate僅代表日期,而不是DateTime。 因此,格式化LocalDate時“HH:mm:ss”沒有任何意義。 假設您想要表示日期和時間,請使用LocalDateTime

我想在@James_D的正確答案中添加以下詳細信息:

背景:大多數日期和時間庫(Java java.util.Calendar ,參見.Net-DateTime或JavaScript中的Date或Perl中的DateTime )基於通用通用唯一時間類型的概念(in德語有詩意的表達“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);    
}

此字段映射並不意味着該字段由具體類型支持。 解析分幾步進行。 字段映射只是第一步。 第二步是解析為TemporalAccessor類型的原始對象。 最后將委托解析為目標類型(此處為: LocalDate ),並讓它決定是否接受已解析的中間對象中的所有字段值。

對我來說合適的課程是ZonedDateTime ,其中包括時區和時區。

LocalDate沒有時間信息,因此您獲得UnsupportedTemporalTypeException: Unsupported field: HourOfDay

您可以使用LocalDateTime但是您沒有時區信息,因此如果您嘗試訪問它(即使使用其中一個預定義的格式化程序),您將收到UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds

我對這段代碼有類似的問題:

DateTimeFormatter.RFC_1123_DATE_TIME.format(new Date().toInstant())

java.time.temporal.UnsupportedTemporalTypeException:不支持的字段:DayOfMonth

我是這樣解決的:

DateTimeFormatter.RFC_1123_DATE_TIME.format(
    ZonedDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()))

Kotlin 2022

fun Long.formatEpochMs(): String {
    val date = ZonedDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
    val pattern = "d, MMMM yyyy"
    return runCatching { DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH).format(date) }
        .onFailure { Timber.e(it) }
        .getOrNull()
        .orEmpty()
}

暫無
暫無

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

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