55import java .text .DateFormat ;
66import java .text .ParseException ;
77import java .text .SimpleDateFormat ;
8+ import java .time .*;
89import java .util .Date ;
910import java .util .TimeZone ;
10- import java .util .concurrent .atomic .AtomicReference ;
11- import java .util .function .Consumer ;
12- import java .util .stream .IntStream ;
1311
1412import static org .assertj .core .api .Assertions .assertThat ;
1513import static org .junit .jupiter .api .Assertions .assertThrows ;
@@ -29,6 +27,85 @@ private static String oldFormat(final Date date) {
2927 return OLD_DATE_FORMAT .format (date );
3028 }
3129
30+ @ Test
31+ void formatInstant () {
32+ Instant instant = Instant .ofEpochMilli (1723642733351L );
33+ assertThat (JavaTimeUtil .format (instant )).isEqualTo ("2024-08-14T13:38:53.351Z" );
34+ }
35+
36+ @ Test
37+ void parseInstant () {
38+ Instant instant = JavaTimeUtil .parseInstant ("2024-08-14T13:38:53.351Z" );
39+ assertThat (instant ).isEqualTo (Instant .ofEpochMilli (1723642733351L ));
40+ }
41+
42+ @ Test
43+ void formatLocalDate () {
44+ LocalDate date = LocalDate .ofInstant (Instant .ofEpochMilli (1723642733351L ), ZoneOffset .UTC );
45+ assertThat (JavaTimeUtil .format (date )).isEqualTo ("2024-08-14" );
46+ }
47+
48+ @ Test
49+ void parseLocalDate () {
50+ LocalDate date = JavaTimeUtil .parseLocalDate ("2024-08-14" );
51+ assertThat (date )
52+ .hasDayOfMonth (14 )
53+ .hasMonth (Month .AUGUST )
54+ .hasYear (2024 );
55+ }
56+
57+ @ Test
58+ void formatOffsetDateTime () {
59+ OffsetDateTime odt = OffsetDateTime .ofInstant (Instant .ofEpochMilli (1723642733351L ), ZoneOffset .UTC );
60+ assertThat (JavaTimeUtil .format (odt )).isEqualTo ("2024-08-14T13:38:53.351Z" );
61+ }
62+
63+ @ Test
64+ void parseOffsetDateTime () {
65+ OffsetDateTime odt = JavaTimeUtil .parseOffsetDateTime ("2024-08-14T13:38:53.351Z" );
66+ assertThat (odt .toInstant ().toEpochMilli ()).isEqualTo (1723642733351L );
67+ }
68+
69+ @ Test
70+ void formatLocalDateTime () {
71+ LocalDateTime ldt = LocalDateTime .ofInstant (Instant .ofEpochMilli (1723642733351L ), ZoneOffset .UTC );
72+ assertThat (JavaTimeUtil .format (ldt )).isEqualTo ("2024-08-14T13:38:53.351" );
73+ }
74+
75+ @ Test
76+ void parseLocalDateTime () {
77+ LocalDateTime ldt = JavaTimeUtil .parseLocalDateTime ("2024-08-14T13:38:53.351" );
78+ assertThat (ldt .toInstant (ZoneOffset .UTC ).toEpochMilli ()).isEqualTo (1723642733351L );
79+ }
80+
81+ @ Test
82+ void formatLocalTime () {
83+ LocalTime lt = LocalTime .ofInstant (Instant .ofEpochMilli (1723642733351L ), ZoneOffset .UTC );
84+ assertThat (JavaTimeUtil .format (lt )).isEqualTo ("13:38:53.351" );
85+ }
86+
87+ @ Test
88+ void parseLocalTime () {
89+ LocalTime lt = JavaTimeUtil .parseLocalTime ("13:38:53.351" );
90+ assertThat (lt )
91+ .hasHour (13 )
92+ .hasMinute (38 )
93+ .hasSecond (53 )
94+ .hasNano (351_000_000 );
95+ }
96+
97+ @ Test
98+ void formatZonedDateTime () {
99+ ZonedDateTime zdt = ZonedDateTime .ofInstant (Instant .ofEpochMilli (1723642733351L ), ZoneOffset .UTC );
100+ assertThat ((JavaTimeUtil .format (zdt ))).isEqualTo ("2024-08-14T13:38:53.351Z" );
101+ }
102+
103+ @ Test
104+ void parseZonedDateTime () {
105+ ZonedDateTime zdt = JavaTimeUtil .parseZonedDateTime ("2024-08-14T13:38:53.351Z" );
106+ assertThat (zdt .toInstant ().toEpochMilli ()).isEqualTo (1723642733351L );
107+ }
108+
32109 @ Test
33110 void roundTrip () throws ParseException {
34111 var input = "2018-04-16T15:17:21.005Z" ;
@@ -69,85 +146,8 @@ void parseException() {
69146
70147 @ Test
71148 void format () {
72- var input = new Date (1723642733350L );
149+ var input = new Date (1723642733351L );
73150 assertThat (JavaTimeUtil .format (input )).isEqualTo (oldFormat (input ));
74151 }
75152
76- @ Test
77- void concurrentParse () {
78- testConcurrent (date -> JavaTimeUtil .parse (JavaTimeUtil .format (date )));
79- }
80-
81- @ Test
82- void oldConcurrentParse () {
83- assertThrows (RuntimeException .class , () -> testConcurrent (date -> oldParse (JavaTimeUtil .format (date ))));
84- }
85-
86- @ Test
87- void concurrentFormat () {
88- testConcurrent (JavaTimeUtil ::format );
89- }
90-
91- @ Test
92- void oldConcurrentFormat () {
93- assertThrows (RuntimeException .class , () -> testConcurrent (JavaTimeUtilTest ::oldFormat ));
94- }
95-
96- private void testConcurrent (ThrowingConsumer <Date > fn ) {
97- AtomicReference <Throwable > e = new AtomicReference <>();
98- Date [] dates ;
99- try {
100- dates = new Date []{
101- JavaTimeUtil .parse ("2018-04-16T15:17:21.005Z" ),
102- JavaTimeUtil .parse ("2019-04-16T15:17:21.020Z" )
103- };
104- } catch (ParseException ex ) {
105- throw new RuntimeException (ex );
106- }
107-
108- var threads = IntStream .range (0 , 16 )
109- .mapToObj (i -> dates [i % dates .length ])
110- .map (date -> new Thread (() -> {
111- for (int j = 0 ; j < 10_000 ; j ++) {
112- fn .accept (date );
113- }
114- }))
115- .toList ();
116-
117- for (Thread t : threads ) {
118- t .setUncaughtExceptionHandler ((th , ex ) -> {
119- e .set (ex );
120- });
121- t .start ();
122- }
123-
124- for (Thread t : threads ) {
125- try {
126- t .join ();
127- } catch (InterruptedException ex ) {
128- throw new RuntimeException (ex );
129- }
130- }
131-
132- Throwable thrown = e .get ();
133- if (thrown != null ) {
134- throw new RuntimeException (thrown );
135- }
136- }
137-
138- @ FunctionalInterface
139- private interface ThrowingConsumer <T > extends Consumer <T > {
140-
141- @ Override
142- default void accept (final T elem ) {
143- try {
144- acceptThrows (elem );
145- } catch (final Exception e ) {
146- throw new RuntimeException (e );
147- }
148- }
149-
150- void acceptThrows (T elem ) throws Exception ;
151- }
152-
153153}
0 commit comments