Skip to content

Commit e917dd0

Browse files
committed
Add org.apache.commons.lang3.time.DateUtils.toOffsetDateTime(Date[,
TimeZone]) #1385
1 parent 0c6a5c1 commit e917dd0

File tree

3 files changed

+125
-70
lines changed

3 files changed

+125
-70
lines changed

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ The <action> type attribute can be add,update,fix,remove.
6969
<action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.lang3.StringUtils.indexOfAny(CharSequence, int, char...).</action>
7070
<action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.lang3.concurrent.ConcurrentException.ConcurrentException(String).</action>
7171
<action type="add" dev="ggregory" due-to="Finger, Gary Gregory, Piotr P. Karwasz">Add org.apache.commons.lang3.time.DateUtils.toLocalDateTime(Date[, TimeZone]) #1385.</action>
72+
<action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.lang3.time.DateUtils.toOffsetDateTime(Date[, TimeZone]) #1385.</action>
7273
<!-- UPDATE -->
7374
<action type="update" dev="ggregory" due-to="Gary Gregory">[test] Bump org.apache.commons:commons-text from 1.13.1 to 1.14.0.</action>
7475
</release>

src/main/java/org/apache/commons/lang3/time/DateUtils.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.text.ParseException;
2020
import java.text.ParsePosition;
2121
import java.time.LocalDateTime;
22+
import java.time.OffsetDateTime;
23+
import java.time.ZoneId;
2224
import java.util.Calendar;
2325
import java.util.Date;
2426
import java.util.Iterator;
@@ -1647,7 +1649,34 @@ public static LocalDateTime toLocalDateTime(final Date date) {
16471649
* @since 3.19.0
16481650
*/
16491651
public static LocalDateTime toLocalDateTime(final Date date, final TimeZone timeZone) {
1650-
return LocalDateTime.ofInstant(date.toInstant(), TimeZones.toTimeZone(timeZone).toZoneId());
1652+
return LocalDateTime.ofInstant(date.toInstant(), toZoneId(timeZone));
1653+
}
1654+
1655+
/**
1656+
* Converts a {@link Date} to a {@link OffsetDateTime}.
1657+
*
1658+
* @param date the Date to convert, not null.
1659+
* @return a new OffsetDateTime.
1660+
* @since 3.19.0
1661+
*/
1662+
public static OffsetDateTime toOffsetDateTime(final Date date) {
1663+
return toOffsetDateTime(date, TimeZone.getDefault());
1664+
}
1665+
1666+
/**
1667+
* Converts a {@link Date} to a {@link OffsetDateTime}.
1668+
*
1669+
* @param date the Date to convert to a OffsetDateTime, not null.
1670+
* @param timeZone the time zone, null maps to to the default time zone.
1671+
* @return a new OffsetDateTime.
1672+
* @since 3.19.0
1673+
*/
1674+
public static OffsetDateTime toOffsetDateTime(final Date date, final TimeZone timeZone) {
1675+
return OffsetDateTime.ofInstant(date.toInstant(), toZoneId(timeZone));
1676+
}
1677+
1678+
private static ZoneId toZoneId(final TimeZone timeZone) {
1679+
return TimeZones.toTimeZone(timeZone).toZoneId();
16511680
}
16521681

16531682
/**

src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java

Lines changed: 94 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@
3030
import java.text.DateFormat;
3131
import java.text.ParseException;
3232
import java.text.SimpleDateFormat;
33+
import java.time.Instant;
3334
import java.time.LocalDateTime;
35+
import java.time.OffsetDateTime;
3436
import java.time.ZoneId;
3537
import java.time.ZoneOffset;
38+
import java.time.temporal.ChronoUnit;
3639
import java.util.Calendar;
3740
import java.util.Date;
3841
import java.util.GregorianCalendar;
@@ -65,70 +68,6 @@ class DateUtilsTest extends AbstractLangTest {
6568
private static final TimeZone TIME_ZONE_MET = TimeZone.getTimeZone("MET");
6669
private static Date BASE_DATE;
6770

68-
private static Stream<Arguments> testToLocalDateTimeTimeZone() {
69-
// @formatter:off
70-
return Stream.of(
71-
Arguments.of(
72-
LocalDateTime.ofInstant(
73-
java.sql.Timestamp.valueOf("2000-01-01 12:30:45").toInstant(),
74-
TimeZone.getTimeZone("America/New_York").toZoneId()
75-
),
76-
java.sql.Timestamp.valueOf("2000-01-01 12:30:45"),
77-
TimeZone.getTimeZone("America/New_York")
78-
),
79-
Arguments.of(
80-
LocalDateTime.ofInstant(
81-
java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
82-
TimeZone.getTimeZone("America/New_York").toZoneId()
83-
),
84-
java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
85-
TimeZone.getTimeZone("America/New_York")
86-
),
87-
Arguments.of(
88-
LocalDateTime.ofInstant(
89-
java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
90-
TimeZone.getDefault().toZoneId()
91-
),
92-
java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
93-
null
94-
),
95-
Arguments.of(
96-
LocalDateTime.of(2022, 12, 31, 19, 0),
97-
Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
98-
.atOffset(ZoneOffset.UTC)
99-
.toInstant()),
100-
TimeZone.getTimeZone("America/New_York")
101-
),
102-
Arguments.of(
103-
LocalDateTime.of(2023, 3, 12, 3, 0),
104-
Date.from(LocalDateTime.of(2023, 3, 12, 7, 0)
105-
.atOffset(ZoneOffset.UTC)
106-
.toInstant()),
107-
TimeZone.getTimeZone("America/New_York")
108-
),
109-
Arguments.of(
110-
LocalDateTime.of(2023, 1, 1, 14, 0),
111-
Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
112-
.atOffset(ZoneOffset.UTC)
113-
.toInstant()),
114-
TimeZone.getTimeZone("Pacific/Kiritimati")
115-
)
116-
);
117-
// @formatter:on
118-
}
119-
120-
@ParameterizedTest
121-
@MethodSource
122-
void testToLocalDateTimeTimeZone(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
123-
assertEquals(expected, DateUtils.toLocalDateTime(date, timeZone));
124-
}
125-
126-
@Test
127-
void testToLocalDateTime() {
128-
final Date date = new Date();
129-
assertEquals(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), DateUtils.toLocalDateTime(date));
130-
}
131-
13271
/**
13372
* Used to check that Calendar objects are close enough
13473
* delta is in milliseconds
@@ -195,9 +134,74 @@ public static void classSetup() {
195134
BASE_DATE = cal.getTime();
196135
}
197136

137+
private static Stream<Arguments> testToLocalDateTimeTimeZone() {
138+
// @formatter:off
139+
return Stream.of(
140+
Arguments.of(
141+
LocalDateTime.ofInstant(Instant.EPOCH, TimeZone.getTimeZone("GMT").toZoneId()),
142+
java.sql.Timestamp.valueOf("1970-01-01 00:00:00"),
143+
TimeZone.getTimeZone("America/New_York")
144+
),
145+
Arguments.of(
146+
LocalDateTime.ofInstant(Instant.EPOCH.minus(1, ChronoUnit.DAYS), TimeZone.getTimeZone("GMT").toZoneId()),
147+
java.sql.Timestamp.valueOf("1969-12-31 00:00:00"),
148+
TimeZone.getTimeZone("America/New_York")
149+
),
150+
Arguments.of(
151+
LocalDateTime.ofInstant(
152+
java.sql.Timestamp.valueOf("2000-01-01 12:30:45").toInstant(),
153+
TimeZone.getTimeZone("America/New_York").toZoneId()
154+
),
155+
java.sql.Timestamp.valueOf("2000-01-01 12:30:45"),
156+
TimeZone.getTimeZone("America/New_York")
157+
),
158+
Arguments.of(
159+
LocalDateTime.ofInstant(
160+
java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
161+
TimeZone.getTimeZone("America/New_York").toZoneId()
162+
),
163+
java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
164+
TimeZone.getTimeZone("America/New_York")
165+
),
166+
Arguments.of(
167+
LocalDateTime.ofInstant(
168+
java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
169+
TimeZone.getDefault().toZoneId()
170+
),
171+
java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
172+
null
173+
),
174+
Arguments.of(
175+
LocalDateTime.of(2022, 12, 31, 19, 0),
176+
Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
177+
.atOffset(ZoneOffset.UTC)
178+
.toInstant()),
179+
TimeZone.getTimeZone("America/New_York")
180+
),
181+
Arguments.of(
182+
LocalDateTime.of(2023, 3, 12, 3, 0),
183+
Date.from(LocalDateTime.of(2023, 3, 12, 7, 0)
184+
.atOffset(ZoneOffset.UTC)
185+
.toInstant()),
186+
TimeZone.getTimeZone("America/New_York")
187+
),
188+
Arguments.of(
189+
LocalDateTime.of(2023, 1, 1, 14, 0),
190+
Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
191+
.atOffset(ZoneOffset.UTC)
192+
.toInstant()),
193+
TimeZone.getTimeZone("Pacific/Kiritimati")
194+
)
195+
);
196+
// @formatter:on
197+
}
198+
198199
private DateFormat dateParser;
200+
199201
private DateFormat dateTimeParser;
202+
200203
private Date dateAmPm1;
204+
201205
private Date dateAmPm2;
202206
private Date dateAmPm3;
203207
private Date dateAmPm4;
@@ -222,13 +226,11 @@ public static void classSetup() {
222226
private Calendar cal6;
223227
private Calendar cal7;
224228
private Calendar cal8;
225-
226229
@AfterEach
227230
public void afterEachResetTimeZones() {
228231
TimeZone.setDefault(TIME_ZONE_DEFAULT);
229232
dateTimeParser.setTimeZone(TIME_ZONE_DEFAULT);
230233
}
231-
232234
private void assertDate(final Date date, final int year, final int month, final int day, final int hour, final int min, final int sec, final int mil) {
233235
final GregorianCalendar cal = new GregorianCalendar();
234236
cal.setTime(date);
@@ -240,7 +242,6 @@ private void assertDate(final Date date, final int year, final int month, final
240242
assertEquals(sec, cal.get(Calendar.SECOND));
241243
assertEquals(mil, cal.get(Calendar.MILLISECOND));
242244
}
243-
244245
@BeforeEach
245246
public void setUp() throws Exception {
246247
dateParser = new SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH);
@@ -1303,10 +1304,34 @@ void testToCalendarWithTimeZoneNull() {
13031304
assertNullPointerException(() -> DateUtils.toCalendar(date1, null));
13041305
}
13051306

1307+
@ParameterizedTest
1308+
@MethodSource("testToLocalDateTimeTimeZone")
1309+
void testToLocalDateTime(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
1310+
assertEquals(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), DateUtils.toLocalDateTime(date));
1311+
}
1312+
1313+
@ParameterizedTest
1314+
@MethodSource
1315+
void testToLocalDateTimeTimeZone(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
1316+
assertEquals(expected, DateUtils.toLocalDateTime(date, timeZone));
1317+
}
1318+
1319+
@ParameterizedTest
1320+
@MethodSource("testToLocalDateTimeTimeZone")
1321+
void testToOffsetDateTime(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
1322+
assertEquals(OffsetDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), DateUtils.toOffsetDateTime(date));
1323+
}
1324+
1325+
@ParameterizedTest
1326+
@MethodSource("testToLocalDateTimeTimeZone")
1327+
void testToOffsetDateTimeTimeZone(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
1328+
assertEquals(expected, DateUtils.toOffsetDateTime(date, timeZone).toLocalDateTime());
1329+
}
1330+
13061331
/**
1307-
* Tests various values with the trunc method
1332+
* Tests various values with the trunc method.
13081333
*
1309-
* @throws Exception so we don't have to catch it
1334+
* @throws Exception so we don't have to catch it.
13101335
*/
13111336
@Test
13121337
void testTruncate() throws Exception {

0 commit comments

Comments
 (0)