喷气小马

Java DateTimeFormatter 初识(一)

📅 ( 更新 ) | 🏷️
文章目录

今天趁着有空闲时间看了 Java8 DateTimeFormatter 的文档总算对 Java 的时间格式有了基本的认识,这里做个笔记记录一下。

时间格式化字符串定义

该表来自于 DateTimeFormatter JDK 8 官方文档

格式字符意义描述例子
GeratextAD; Anno Domini; A
uyearyear2004; 04
yyear-of-erayear2004; 04
Dday-of-yearnumber189
M/Lmonth-of-yearnumber/text7; 07; Jul; July; J
dday-of-monthnumber10
Q/qquarter-of-yearnumber/text3; 03; Q3; 3rd quarter
Yweek-based-yearyear1996; 96
wweek-of-week-based-yearnumber27
Wweek-of-monthnumber4
Eday-of-weektextTue; Tuesday; T
e/clocalized day-of-weeknumber/text2; 02; Tue; Tuesday; T
Fweek-of-monthnumber3
aam-pm-of-daytextPM
hclock-hour-of-am-pm (1-12)number12
Khour-of-am-pm (0-11)number0
kclock-hour-of-am-pm (1-24)number0
Hhour-of-day (0-23)number0
mminute-of-hournumber30
ssecond-of-minutenumber55
Sfraction-of-secondfraction978
Amilli-of-daynumber1234
nnano-of-secondnumber987654321
Nnano-of-daynumber1234000000
Vtime-zone IDzone-idAmerica/Los_Angeles; Z; -08:30
ztime-zone namezone-namePacific Standard Time; PST
Olocalized zone-offsetoffset-OGMT+8; GMT+08:00; UTC-08:00;
Xzone-offset 'Z' for zerooffset-XZ; -08; -0830; -08:30; -083015; -08:30:15;
xzone-offsetoffset-x+0000; -08; -0830; -08:30; -083015; -08:30:15;
Zzone-offsetoffset-Z+0000; -0800; -08:00;
ppad nextpad modifier1
'escape for textdelimiter
''single quoteliteral'
[optional section start
]optional section end
'#reserved for future use
{reserved for future use
}reserved for future use

年份格式

和年份有关的格式化字符有 4 个分别是: G,u,y,Y

G:纪年标志

G 纪元标识,显示当前年份属于公元前还是公元后。要注意的是:yyyy 格式下不存在公元前零年, 或者公元后零年。年份从一开始,年份值为零时对应的是公元前一年。

1  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("G yyyy");
2  formatter.format(LocalDate.of(1,1,1));//结果:公元 0001
3  formatter.format(LocalDate.of(0,1,1));//结果:公元前 0001
4  formatter.format(LocalDate.of(-1,1,1));//结果:公元前 0002

u,y,Y:年份标志

prolptic-year:u/Y 和 year-of-ear:y 的差别

u,y,Y 都是年份格式字符串。但是区别在于 u/Y 是 prolptic-year y 属于 year-of-era。二者的差别可详见 Stack Overflow

简略的来说 u/Y 在年份为公元前时会将年份转换为从零开始的负数,而 y 在 转换公元前的年份时则是从一开始递增。

1DateTimeFormatter formatter =
2                DateTimeFormatter.ofPattern("'proleptic-year:' u Y G '-- era-year:' y G");
3formatter.format(LocalDate.of(2,3,1));//结果:proleptic-year: 2 2 公元 -- era-year: 2 公元
4formatter.format(LocalDate.of(1,3,1));//结果:proleptic-year: 1 1 公元 -- era-year: 1 公元
5formatter.format(LocalDate.of(0,3,1));//结果:proleptic-year: 0 0 公元前 -- era-year: 1 公元前
6formatter.format(LocalDate.of(-1,3,1));//结果:proleptic-year: -1 -1 公元前 -- era-year: 2 公元前

year-of-ear:y 和 week-based-year:Y 的差别

y 和 Y 的差别在于第一周存在跨年时 YYYY 会根据 WeekFields 中 firstDayOfWeek(每周 第一天) 和 minimalDays(当年第一周天数最小数) 属性值来计算跨年周属于哪一年。从每 周第一天开始计算如果在新年的天数大于等于第一周天数最小数那么跨年周属于新年的第一 周,否则属于旧年的最后一周。同时改周内所有的天数年分都会被设定为周所在年份,这也 就是为什么不推荐使用 YYYY 格式化年份的原因。

DateTimeFormatter 中 WeekFields 上述两个字段的默认值由 Locale 决定。WeekFields 默认有两种规则 ISO(起始天为周一,第一周最少 4 天)和 SUNDAY_START(起始天为周四, 第一周最少 1 天) 。

要注意的是 Locale.CHINA 默认使用的是 SUNDAY_START。

1  LocalDate date = LocalDate.of(2022, 1, 1);
2  DateTimeFormatter formatterUK =
3      DateTimeFormatter.ofPattern("YYYY-MM-dd '第'ww'周'", Locale.UK);
4  DateTimeFormatter formatterCN =
5      DateTimeFormatter.ofPattern("YYYY-MM-dd '第'ww'周'",Locale.CHINA);
6  System.out.printf("中国时间:%s\n",formatterCN.format(date));//结果:中国时间:2022-01-01 01
7  System.out.printf("英国时间:%s\n",formatterUK.format(date));//结果:英国时间:2021-01-01 52 因为跨年周在2021年有5天所以被判定为 2021 年

季度格式

季度相关的格式化字符只有 Q/q 两个,规则都是从一月开始每三个月算一个季度。 唯一不同的在于格式化结果不一样,q 格式除了 qq 显示 01 外,其他数量的 q 都显示为 1 。 而 Q 格式则是不同数量的 Q 在不同地区下有着不同的格式化结果。

格式英语地区中文地区
Q11
QQ0101
QQQQ11 季
QQQQ1st quarter第 1 季度
QQQQQ11

月份格式

月份格式也只有两个: M/L ,两个格式大同小异,区别在于 M 能支持更多的格式结果

格式英语地区中文地区
M/L1/11/1
MM/LL01/0101/01
MMM/LLLJan/1一月/一月
MMMM/LLLLJanuary/1一月/一月
MMMMM/LLLLLJ/11/一月

周格式

周格式有三个:W(基于月的周数),w(基于 Y 格式的周数)。

其中格式 w 在遭遇跨年时会按照 WeekFields 的规则来进行周数判断,格式化的结果时该 周在当年属于第几周。
而格式 W ,则是在遭遇跨月时按照 WeekFields 的规则来判断。如 果该周在新月份中的天数小于 WeekFields 中的一周最小天数,那么结果为 0 ,反之为 1。

时间格式英语地区中文地区
2022-01-01W/w0/521/1
2022-01-05W/w1/12/2
2022-04-01W/w0/131/14

天格式

关于天的格式有:D, d , E , F , e , c

格式规则日期例子结果备注
D查找该天在当年是第几天2022-02-1041
d查找该天在当月是第几天2022-02-1010
E查找该天在当周是第几天2022-02-10Thu;Thursday;星期四受地区影响有本地化输出
e/c根据 WeekFields 的firstDayOfWeek 来判定该天在当周是第几天2022-02-104受地区影响有本地化输出
F把每月一号当作第一周的第一天,来计算当天属于周内第几天2022-02-103JDK8 官方文档错误,11 已纠正

小时格式

关于小时的格式有:a,h,K,k,H

格式规则日期例子结果备注
a上午还是下午标志2022-02-10 13:00:00PM;下午受Local 影响有本地化输出
h时钟式时间 1-122022-02-10 13:00:001;0112:00 输出为 12
K12小时制时间 0-112022-02-10 13:00:001;0112:00 输出为 00
k时钟式时间 1-242022-02-10 13:00:001300:00 输出为 24
H24小时制 0-232022-02-10 13:00:001300:00 输出为 00

分秒格式

关于分和秒的格式有: m,s,S,A,n,N

格式规则日期例子结果备注
m小时内的分钟值13:10:0010
s分钟内的秒值13:10:1111
S毫秒值 0-99913:10:12.434434
A对应时间是当天的第多少毫秒14:00:00.12350400123一秒等于一千毫秒
n秒内的纳秒数14:00:00.123123000000一百万纳秒等于一毫米
N对应时间是当天的第多少纳秒14:00:00.12350400123000000

额外格式

格式规则日期例子结果备注
VV输出当前时区Id14:00:00Asia/Shanghai1.只接受VV,其他个数的V会抛出异常。2.只能用来格式化 ZonedDateTime
z输出当前时区名14:00:00CST注意美国中部时间和北京时间都是 CST