Java DateFormat lowercase vs uppercase

Introduction

Java's DateTimeFormatter uses the fixed half-width alphabetic characters to decide what kind of character string to use. Among them, there are many strings such as y and Y that try to express different things only by the difference between uppercase and lowercase letters. Here is a summary of the differences.

environment

Maybe Java has no version difference, but I'm using Java 11. Jshell is useful for drawing short code like this time, so I'm trying it on JShell.

After starting, import the class that you will use ,.

tasogarei $ jshell
|Welcome to JShell--Version 11.0.1
|For an overview, type:: /help intro

jshell> import java.time.*

jshell> import java.time.format.DateTimeFormatter

g vs G g represents Julian Day and G represents the era.

jshell> LocalDateTime.now().format(DateTimeFormatter.ofPattern("g"));
$83 ==> "58499"

jshell> LocalDateTime.now().format(DateTimeFormatter.ofPattern("G"));
$84 ==> "Year"

If you want to know about Julian Day, please see Wikipedia (I also learned for the first time) https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%AA%E3%82%A6%E3%82%B9%E9%80%9A%E6%97%A5

m vs M This is easy: m stands for minutes and M stands for months. If you overlap two of each, it will return a String padded with 0 in the case of one digit, so it is common to describe two if you want to have the same number of digits. In both cases, the number of digits that should be expressed is up to 2 digits, so if 3 are described, an error will occur at runtime.

jshell> LocalDateTime.of(2019,12,12,12,1,1).format(DateTimeFormatter.ofPattern("mmm"));
|Exception java.lang.IllegalArgumentException: Too many pattern letters: m
|        at DateTimeFormatterBuilder.parseField (DateTimeFormatterBuilder.java:1952)
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1734)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#24:1)

However, since M is situation-dependent, it may actually be more correct to use L. Since L is a standalone method, the same value is always displayed. However, only this difference is for SimpleDateFormat, and if you use DateTimeFormatter, both can be used without any problem.

d vs D This seems to have a similar meaning and behaves differently.

First of all, it is d, but it displays the month-based date as" day-of-month "in the explanation. It's the date we commonly use.

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("dd"));
$3 ==> "02"

On the other hand, D is" day-of-year ", which displays the year-based date. It's the number of days since January 1st, the beginning of the year.

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("DDD"));
$4 ==> "033"

y vs Y Before looking at the difference between the two, let's look at the code results to see that the display format differs depending on the number specified. In general, I think that you will either specify two and specify the last two digits or four and have them all displayed. I don't think there are many cases where years other than 4 digits are displayed, so here we will only look at 4 digits.

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("y"));
$5 ==> "2019"

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("yy"));
$6 ==> "19"

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("yyy"));
$7 ==> "2019"

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("yyyy"));
$8 ==> "2019"

The capital letter Y is also used to express the year, so there is no change in the number.

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("Y"));
$9 ==> "2019"

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("YY"));
$10 ==> "19"

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("YYY"));
$11 ==> "2019"

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("YYYY"));
$12 ==> "2019"

And the difference is, first take a look at the code below.

jshell> LocalDate.of(2018,12,30).format(DateTimeFormatter.ofPattern("YYYY"));
$44 ==> "2019"

jshell> LocalDate.of(2018,12,30).format(DateTimeFormatter.ofPattern("yyyy"));
$45 ==> "2018"

Even though I specified the same date, the year is off by one year. This is the difference, because Y is for displaying the year by the Gregorian Calendar and y is for displaying the year of the era, so the difference appears. For the Gregorian Calendar, take a look at the JavaDoc, but it's a good idea to keep in mind that the year-end and New Year holidays can be off. Therefore, it can be a hotbed to embed a bug that seems to pass through just by testing that the year display is incorrect for only a few days during the year-end and New Year holidays. There is no doubt that I had done it a long time ago and had a very bad time.

By the way, y displays the year with respect to the era, so it may not be the value you expected unless the era is in the Christian era. By default, the era is the Christian era (I haven't confirmed it until I changed the locale).

jshell> LocalDate.of(2018,12,30).format(DateTimeFormatter.ofPattern("G"));
$46 ==> "Year"

I don't think it's a big problem, but to be precise, ʻu is used to display the year as it is, so using ʻu may be the correct answer. I think it depends on the way of thinking, so I can't say anything.

jshell> LocalDate.of(2018,12,30).format(DateTimeFormatter.ofPattern("u"));
$47 ==> "2018"

k vs K and h vs H

k and K, h and H display the time, but the ones that display them are different. The table below summarizes what is displayed for each.

k K h H
1-24 0-11 1-12 0-23

There is a big difference that lowercase letters are written at 24 o'clock and uppercase letters are written at 12 hours, and if k and h are 0 o'clock, it will be 24 (12) o'clock.

w vs W Both w and W are similar expressions for the week, but they have different criteria. The difference is that w displays the number of laps of the month for W of the year.

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("W"));
$55 ==> "1"

jshell> LocalDate.of(2019,2,2).format(DateTimeFormatter.ofPattern("w"));
$56 ==> "5"

s vs S s represents the general second, while S represents the fraction-of-second.

jshell> LocalDateTime.now().format(DateTimeFormatter.ofPattern("s"));
$57 ==> "24"

jshell> LocalDateTime.now().format(DateTimeFormatter.ofPattern("S"));
$58 ==> "7"

I don't really understand S, so I specified more than one and looked at the difference in operation.

jshell> LocalDateTime.of(2019,1,1,0,0,12,10);
$75 ==> 2019-01-01T00:00:12.000000010

jshell> LocalDateTime.of(2019,1,1,0,0,12,10).format(DateTimeFormatter.ofPattern("SSS"));
$76 ==> "000"

jshell> LocalDateTime.of(2019,1,1,0,0,12,10).format(DateTimeFormatter.ofPattern("SSSS"));
$77 ==> "0000"

jshell> LocalDateTime.of(2019,1,1,0,0,12,10).format(DateTimeFormatter.ofPattern("SSSSS"));
$78 ==> "00000"

jshell> LocalDateTime.of(2019,1,1,0,0,12,10).format(DateTimeFormatter.ofPattern("SSSSSS"));
$79 ==> "000000"

jshell> LocalDateTime.of(2019,1,1,0,0,12,10).format(DateTimeFormatter.ofPattern("SSSSSSS"));
$80 ==> "0000000"

jshell> LocalDateTime.of(2019,1,1,0,0,12,10).format(DateTimeFormatter.ofPattern("SSSSSSSS"));
$81 ==> "00000001"

jshell> LocalDateTime.of(2019,1,1,0,0,12,10).format(DateTimeFormatter.ofPattern("SSSSSSSSS"));
$82 ==> "000000010"

Apparently, it seems to display how many digits are less than a second. It is a level that can be finally discriminated by specifying 10 nanoseconds by specifying ʻof` and seeing the difference in operation.

q vs Q q and Q are rarely synonymous with the number of times in a quarter. I don't know why so many letters have different meanings but they are all the same.

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("q"));
$87 ==> "4"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("Q"));
$88 ==> "4"

e vs E ʻE shows the localized day of the week and ʻE shows the general day of the week.

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("E"));
$96 ==> "fire"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("e"));
$97 ==> "3"

ʻE and ʻE have an interesting behavior that the display changes depending on the specified number, so try changing the specified number.

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("ee"));
$101 ==> "03"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("eee"));
$102 ==> "fire"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("eeee"));
$103 ==> "Tuesday"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("eeeee"));
$104 ==> "fire"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("eeeeee"));
|Exception java.lang.IllegalArgumentException: Too many pattern letters: e
|        at DateTimeFormatterBuilder.parseField (DateTimeFormatterBuilder.java:1903)
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1734)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#105:1)
jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("EE"));
$108 ==> "fire"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("EEE"));
$109 ==> "fire"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("EEEE"));
$110 ==> "Tuesday"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("EEEEE"));
$111 ==> "fire"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("EEEEEE"));
|Exception java.lang.IllegalArgumentException: Too many pattern letters: E
|        at DateTimeFormatterBuilder.parseField (DateTimeFormatterBuilder.java:1903)
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1734)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#112:1)

By the way, I didn't really understand the case where the display of localized days and general days of the week changed.

By the way, c is said to be displayed the same as ʻe, but if you specify two or more, an error will occur. It seems that the type of c handles numbers with number and ʻe handles strings with text.

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("c"));
$113 ==> "3"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("cc"));
|Exception java.lang.IllegalArgumentException: Invalid pattern "cc"
|        at DateTimeFormatterBuilder.parseField (DateTimeFormatterBuilder.java:1867)
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1734)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#114:1)

Also, please note that ʻe and care not defined inSimpleDateFormatter and appear from DateTimeFormatter`.

jshell> new SimpleDateFormat("E").format(new Date())
$144 ==> "water"

jshell> new SimpleDateFormat("e").format(new Date())
|Exception java.lang.IllegalArgumentException: Illegal pattern character 'e'
|        at SimpleDateFormat.compile (SimpleDateFormat.java:845)
|        at SimpleDateFormat.initialize (SimpleDateFormat.java:653)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:624)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:599)
|        at (#145:1)

jshell> new SimpleDateFormat("c").format(new Date())
|Exception java.lang.IllegalArgumentException: Illegal pattern character 'c'
|        at SimpleDateFormat.compile (SimpleDateFormat.java:845)
|        at SimpleDateFormat.initialize (SimpleDateFormat.java:653)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:624)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:599)
|        at (#146:1)

a vs A ʻA represents the morning and afternoon of the day, and ʻA represents how many ms have passed in the day.

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("a"));
$147 ==> "a.m."

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("A"));
$148 ==> "12000"

n VS N n represents the nanosecond portion of the time, and N represents how many ns have passed in the day.

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("n"));
$149 ==> "10"

jshell> LocalDateTime.of(2019,10,1,0,0,12,10).format(DateTimeFormatter.ofPattern("N"));
$150 ==> "12000000010"

v vs V v represents a common time zone name and V represents a time zone ID. As for V, if there is only one, an error will occur, so you need to specify two as VV.

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("v"));
$159 ==> "GMT+09:00"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("VV"));
$160 ==> "Asia/Tokyo"

Since these want to express the time zone, an error will occur in the LocalDate system that does not have the concept of time zone. Caution is required.

jshell> LocalDateTime.now().format(DateTimeFormatter.ofPattern("VV"));
|Exception java.time.DateTimeException: Unable to extract ZoneId from temporal 2019-01-16T17:33:36.488440
|        at DateTimePrintContext.getValue (DateTimePrintContext.java:289)
|        at DateTimeFormatterBuilder$ZoneIdPrinterParser.format (DateTimeFormatterBuilder.java:4170)
|        at DateTimeFormatterBuilder$CompositePrinterParser.format (DateTimeFormatterBuilder.java:2335)
|        at DateTimeFormatter.formatTo (DateTimeFormatter.java:1843)
|        at DateTimeFormatter.format (DateTimeFormatter.java:1817)
|        at LocalDateTime.format (LocalDateTime.java:1752)
|        at (#161:1)

jshell> LocalDateTime.now().format(DateTimeFormatter.ofPattern("v"));
|Exception java.time.DateTimeException: Unable to extract ZoneId from temporal 2019-01-16T17:33:39.394345
|        at DateTimePrintContext.getValue (DateTimePrintContext.java:289)
|        at DateTimeFormatterBuilder$ZoneTextPrinterParser.format (DateTimeFormatterBuilder.java:4066)
|        at DateTimeFormatterBuilder$CompositePrinterParser.format (DateTimeFormatterBuilder.java:2335)
|        at DateTimeFormatter.formatTo (DateTimeFormatter.java:1843)
|        at DateTimeFormatter.format (DateTimeFormatter.java:1817)
|        at LocalDateTime.format (LocalDateTime.java:1752)
|        at (#162:1)

By the way, JapaneseDate, which shows the date in Japan, also causes an error.

jshell> import java.time.chrono.*

jshell> JapaneseDate.now().format(DateTimeFormatter.ofPattern("v"));
|Exception java.time.DateTimeException: Unable to extract ZoneId from temporal Japanese Heisei 31-01-16
|        at DateTimePrintContext.getValue (DateTimePrintContext.java:289)
|        at DateTimeFormatterBuilder$ZoneTextPrinterParser.format (DateTimeFormatterBuilder.java:4066)
|        at DateTimeFormatterBuilder$CompositePrinterParser.format (DateTimeFormatterBuilder.java:2335)
|        at DateTimeFormatter.formatTo (DateTimeFormatter.java:1843)
|        at DateTimeFormatter.format (DateTimeFormatter.java:1817)
|        at ChronoLocalDate.format (ChronoLocalDate.java:642)
|        at (#164:1)

jshell> JapaneseDate.now().format(DateTimeFormatter.ofPattern("VV"));
|Exception java.time.DateTimeException: Unable to extract ZoneId from temporal Japanese Heisei 31-01-16
|        at DateTimePrintContext.getValue (DateTimePrintContext.java:289)
|        at DateTimeFormatterBuilder$ZoneIdPrinterParser.format (DateTimeFormatterBuilder.java:4170)
|        at DateTimeFormatterBuilder$CompositePrinterParser.format (DateTimeFormatterBuilder.java:2335)
|        at DateTimeFormatter.formatTo (DateTimeFormatter.java:1843)
|        at DateTimeFormatter.format (DateTimeFormatter.java:1817)
|        at ChronoLocalDate.format (ChronoLocalDate.java:642)
|        at (#165:1)

z vs Z z represents the time zone name and Z represents the zone-offset. I thought that it would cause a serious situation if I started to talk about things that are not generally attached, so I will omit them here.

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("z"));
$166 ==> "JST"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("Z"));
$167 ==> "+0900"

The display of z and Z also changes depending on the specified number, so I would like to specify it.

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("z"));
$174 ==> "JST"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("zz"));
$175 ==> "JST"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("zzz"));
$176 ==> "JST"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("zzzz"));
$177 ==> "Japan Standard Time"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("zzzzz"));
|Exception java.lang.IllegalArgumentException: Too many pattern letters: z
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1737)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#178:1)
jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("Z"));
$180 ==> "+0900"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("ZZ"));
$181 ==> "+0900"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("ZZZ"));
$182 ==> "+0900"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("ZZZZ"));
$183 ==> "GMT+09:00"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("ZZZZZ"));
$184 ==> "+09:00"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("ZZZZZZ"));
|Exception java.lang.IllegalArgumentException: Too many pattern letters: Z
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1764)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#185:1)

Note that z and Z behave differently from SimpleDateFormatter.

jshell> new SimpleDateFormat("Z").format(new Date());
$219 ==> "+0900"

jshell> new SimpleDateFormat("ZZ").format(new Date());
$220 ==> "+0900"

jshell> new SimpleDateFormat("ZZZ").format(new Date());
$221 ==> "+0900"

jshell> new SimpleDateFormat("ZZZZ").format(new Date());
$222 ==> "+0900"

jshell> new SimpleDateFormat("ZZZZZ").format(new Date());
$223 ==> "+0900"

jshell> new SimpleDateFormat("ZZZZZZ").format(new Date());
$224 ==> "+0900"
jshell> new SimpleDateFormat("z").format(new Date());
$210 ==> "JST"

jshell> new SimpleDateFormat("zz").format(new Date());
$211 ==> "JST"

jshell> new SimpleDateFormat("zzz").format(new Date());
$212 ==> "JST"

jshell> new SimpleDateFormat("zzzz").format(new Date());
$213 ==> "Japan Standard Time"

jshell> new SimpleDateFormat("zzzzz").format(new Date());
$214 ==> "Japan Standard Time"

jshell> new SimpleDateFormat("zzzzzz").format(new Date());
$215 ==> "Japan Standard Time"

jshell> new SimpleDateFormat("zzzzzzz").format(new Date());
$216 ==> "Japan Standard Time"

jshell> new SimpleDateFormat("zzzzzzzz").format(new Date());
$217 ==> "Japan Standard Time"

By the way, I tried to specify the number, but no error occurred.

x vs X Both x and X represent zone-offset, which seems to behave the same except for UTC. The only difference from Z is that the display changes when 1 and 4 are specified.

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("x"));
$186 ==> "+09"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("X"));
$187 ==> "+09
jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("x"));
$188 ==> "+09"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("xx"));
$189 ==> "+0900"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("xxx"));
$190 ==> "+09:00"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("xxxx"));
$191 ==> "+0900"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("xxxxx"));
$192 ==> "+09:00"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("xxxxxx"));
|Exception java.lang.IllegalArgumentException: Too many pattern letters: x
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1781)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#193:1)
jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("X"));
$194 ==> "+09"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("XX"));
$195 ==> "+0900"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("XXX"));
$196 ==> "+09:00"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("XXXX"));
$197 ==> "+0900"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("XXXXX"));
$198 ==> "+09:00"

jshell> ZonedDateTime.now().format(DateTimeFormatter.ofPattern("XXXXXX"));
|Exception java.lang.IllegalArgumentException: Too many pattern letters: X
|        at DateTimeFormatterBuilder.parsePattern (DateTimeFormatterBuilder.java:1776)
|        at DateTimeFormatterBuilder.appendPattern (DateTimeFormatterBuilder.java:1702)
|        at DateTimeFormatter.ofPattern (DateTimeFormatter.java:564)
|        at (#199:1)

By the way, x does not exist in SimpleDateFormatter, only DateTimeFormatter.

jshell> new SimpleDateFormat("x").format(new Date());
|Exception java.lang.IllegalArgumentException: Illegal pattern character 'x'
|        at SimpleDateFormat.compile (SimpleDateFormat.java:845)
|        at SimpleDateFormat.initialize (SimpleDateFormat.java:653)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:624)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:599)
|        at (#205:1)

Note that the behavior of X is also different.

jshell> new SimpleDateFormat("X").format(new Date());
$206 ==> "+09"

jshell> new SimpleDateFormat("XX").format(new Date());
$207 ==> "+0900"

jshell> new SimpleDateFormat("XXX").format(new Date());
$208 ==> "+09:00"

jshell> new SimpleDateFormat("XXXX").format(new Date());
|Exception java.lang.IllegalArgumentException: invalid ISO 8601 format: length=4
|        at SimpleDateFormat.encode (SimpleDateFormat.java:884)
|        at SimpleDateFormat.compile (SimpleDateFormat.java:865)
|        at SimpleDateFormat.initialize (SimpleDateFormat.java:653)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:624)
|        at SimpleDateFormat.<init> (SimpleDateFormat.java:599)
|        at (#209:1)

You will not be aware of the difference that occurs only in UTC because the time in JST is usually output, but I think you should just remember to be careful about UTC. I finally understood it by looking at the implementation.

jshell> ZonedDateTime.of(2019,1,1,1,1,1,1,ZoneId.of(ZoneOffset.UTC.toString())).format(DateTimeFormatter.ofPattern("X"));
$228 ==> "Z"

jshell> ZonedDateTime.of(2019,1,1,1,1,1,1,ZoneId.of(ZoneOffset.UTC.toString())).format(DateTimeFormatter.ofPattern("x"));
$229 ==> "+00"

at the end

It turned out to be scarier than I expected because there are many points where the behavior is different from SimpleDateFormatter and the time zone is suspicious. To be honest, I didn't use the function so much, so I don't know what is correct at the moment, but if I have time, I would like to see the implementation on the Java side.

Recommended Posts

Java DateFormat lowercase vs uppercase
Java --StringBuilder vs StringBuffer
[Java] Convert character strings to uppercase / lowercase (AOJ⑨-swap uppercase and lowercase)
Kana uppercase ⇔ lowercase conversion in Java, voiced / semi-voiced sound mark deleted
Java Spring environment in vs Code
Java build with mac vs code
Java development environment (Mac, VS Code)