[英]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.