You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2025/08/24 19:43:30 UTC
(commons-lang) 01/02: Add org.apache.commons.lang3.time.DateUtils.toOffsetDateTime(Date[, TimeZone]) #1385
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
commit e917dd0df3cd38b8ee7e7bbf3ba75fa6f8f06e40
Author: Gary D. Gregory <ga...@gmail.com>
AuthorDate: Sat Aug 23 07:46:15 2025 -0400
Add org.apache.commons.lang3.time.DateUtils.toOffsetDateTime(Date[,
TimeZone]) #1385
---
src/changes/changes.xml | 1 +
.../org/apache/commons/lang3/time/DateUtils.java | 31 +++-
.../apache/commons/lang3/time/DateUtilsTest.java | 163 ++++++++++++---------
3 files changed, 125 insertions(+), 70 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6fac9d6d2..112a79604 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -69,6 +69,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.lang3.StringUtils.indexOfAny(CharSequence, int, char...).</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.lang3.concurrent.ConcurrentException.ConcurrentException(String).</action>
<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>
+ <action type="add" dev="ggregory" due-to="Gary Gregory">Add org.apache.commons.lang3.time.DateUtils.toOffsetDateTime(Date[, TimeZone]) #1385.</action>
<!-- UPDATE -->
<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>
</release>
diff --git a/src/main/java/org/apache/commons/lang3/time/DateUtils.java b/src/main/java/org/apache/commons/lang3/time/DateUtils.java
index 061ab2aa3..990189147 100644
--- a/src/main/java/org/apache/commons/lang3/time/DateUtils.java
+++ b/src/main/java/org/apache/commons/lang3/time/DateUtils.java
@@ -19,6 +19,8 @@
import java.text.ParseException;
import java.text.ParsePosition;
import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
@@ -1647,7 +1649,34 @@ public static LocalDateTime toLocalDateTime(final Date date) {
* @since 3.19.0
*/
public static LocalDateTime toLocalDateTime(final Date date, final TimeZone timeZone) {
- return LocalDateTime.ofInstant(date.toInstant(), TimeZones.toTimeZone(timeZone).toZoneId());
+ return LocalDateTime.ofInstant(date.toInstant(), toZoneId(timeZone));
+ }
+
+ /**
+ * Converts a {@link Date} to a {@link OffsetDateTime}.
+ *
+ * @param date the Date to convert, not null.
+ * @return a new OffsetDateTime.
+ * @since 3.19.0
+ */
+ public static OffsetDateTime toOffsetDateTime(final Date date) {
+ return toOffsetDateTime(date, TimeZone.getDefault());
+ }
+
+ /**
+ * Converts a {@link Date} to a {@link OffsetDateTime}.
+ *
+ * @param date the Date to convert to a OffsetDateTime, not null.
+ * @param timeZone the time zone, null maps to to the default time zone.
+ * @return a new OffsetDateTime.
+ * @since 3.19.0
+ */
+ public static OffsetDateTime toOffsetDateTime(final Date date, final TimeZone timeZone) {
+ return OffsetDateTime.ofInstant(date.toInstant(), toZoneId(timeZone));
+ }
+
+ private static ZoneId toZoneId(final TimeZone timeZone) {
+ return TimeZones.toTimeZone(timeZone).toZoneId();
}
/**
diff --git a/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java b/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java
index 3fbfaadfc..f114f4eb5 100644
--- a/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java
@@ -30,9 +30,12 @@
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.time.Instant;
import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@@ -65,70 +68,6 @@ class DateUtilsTest extends AbstractLangTest {
private static final TimeZone TIME_ZONE_MET = TimeZone.getTimeZone("MET");
private static Date BASE_DATE;
- private static Stream<Arguments> testToLocalDateTimeTimeZone() {
- // @formatter:off
- return Stream.of(
- Arguments.of(
- LocalDateTime.ofInstant(
- java.sql.Timestamp.valueOf("2000-01-01 12:30:45").toInstant(),
- TimeZone.getTimeZone("America/New_York").toZoneId()
- ),
- java.sql.Timestamp.valueOf("2000-01-01 12:30:45"),
- TimeZone.getTimeZone("America/New_York")
- ),
- Arguments.of(
- LocalDateTime.ofInstant(
- java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
- TimeZone.getTimeZone("America/New_York").toZoneId()
- ),
- java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
- TimeZone.getTimeZone("America/New_York")
- ),
- Arguments.of(
- LocalDateTime.ofInstant(
- java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
- TimeZone.getDefault().toZoneId()
- ),
- java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
- null
- ),
- Arguments.of(
- LocalDateTime.of(2022, 12, 31, 19, 0),
- Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
- .atOffset(ZoneOffset.UTC)
- .toInstant()),
- TimeZone.getTimeZone("America/New_York")
- ),
- Arguments.of(
- LocalDateTime.of(2023, 3, 12, 3, 0),
- Date.from(LocalDateTime.of(2023, 3, 12, 7, 0)
- .atOffset(ZoneOffset.UTC)
- .toInstant()),
- TimeZone.getTimeZone("America/New_York")
- ),
- Arguments.of(
- LocalDateTime.of(2023, 1, 1, 14, 0),
- Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
- .atOffset(ZoneOffset.UTC)
- .toInstant()),
- TimeZone.getTimeZone("Pacific/Kiritimati")
- )
- );
- // @formatter:on
- }
-
- @ParameterizedTest
- @MethodSource
- void testToLocalDateTimeTimeZone(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
- assertEquals(expected, DateUtils.toLocalDateTime(date, timeZone));
- }
-
- @Test
- void testToLocalDateTime() {
- final Date date = new Date();
- assertEquals(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), DateUtils.toLocalDateTime(date));
- }
-
/**
* Used to check that Calendar objects are close enough
* delta is in milliseconds
@@ -195,9 +134,74 @@ public static void classSetup() {
BASE_DATE = cal.getTime();
}
+ private static Stream<Arguments> testToLocalDateTimeTimeZone() {
+ // @formatter:off
+ return Stream.of(
+ Arguments.of(
+ LocalDateTime.ofInstant(Instant.EPOCH, TimeZone.getTimeZone("GMT").toZoneId()),
+ java.sql.Timestamp.valueOf("1970-01-01 00:00:00"),
+ TimeZone.getTimeZone("America/New_York")
+ ),
+ Arguments.of(
+ LocalDateTime.ofInstant(Instant.EPOCH.minus(1, ChronoUnit.DAYS), TimeZone.getTimeZone("GMT").toZoneId()),
+ java.sql.Timestamp.valueOf("1969-12-31 00:00:00"),
+ TimeZone.getTimeZone("America/New_York")
+ ),
+ Arguments.of(
+ LocalDateTime.ofInstant(
+ java.sql.Timestamp.valueOf("2000-01-01 12:30:45").toInstant(),
+ TimeZone.getTimeZone("America/New_York").toZoneId()
+ ),
+ java.sql.Timestamp.valueOf("2000-01-01 12:30:45"),
+ TimeZone.getTimeZone("America/New_York")
+ ),
+ Arguments.of(
+ LocalDateTime.ofInstant(
+ java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
+ TimeZone.getTimeZone("America/New_York").toZoneId()
+ ),
+ java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
+ TimeZone.getTimeZone("America/New_York")
+ ),
+ Arguments.of(
+ LocalDateTime.ofInstant(
+ java.sql.Timestamp.valueOf("2023-03-12 02:30:00").toInstant(),
+ TimeZone.getDefault().toZoneId()
+ ),
+ java.sql.Timestamp.valueOf("2023-03-12 02:30:00"),
+ null
+ ),
+ Arguments.of(
+ LocalDateTime.of(2022, 12, 31, 19, 0),
+ Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
+ .atOffset(ZoneOffset.UTC)
+ .toInstant()),
+ TimeZone.getTimeZone("America/New_York")
+ ),
+ Arguments.of(
+ LocalDateTime.of(2023, 3, 12, 3, 0),
+ Date.from(LocalDateTime.of(2023, 3, 12, 7, 0)
+ .atOffset(ZoneOffset.UTC)
+ .toInstant()),
+ TimeZone.getTimeZone("America/New_York")
+ ),
+ Arguments.of(
+ LocalDateTime.of(2023, 1, 1, 14, 0),
+ Date.from(LocalDateTime.of(2023, 1, 1, 0, 0)
+ .atOffset(ZoneOffset.UTC)
+ .toInstant()),
+ TimeZone.getTimeZone("Pacific/Kiritimati")
+ )
+ );
+ // @formatter:on
+ }
+
private DateFormat dateParser;
+
private DateFormat dateTimeParser;
+
private Date dateAmPm1;
+
private Date dateAmPm2;
private Date dateAmPm3;
private Date dateAmPm4;
@@ -222,13 +226,11 @@ public static void classSetup() {
private Calendar cal6;
private Calendar cal7;
private Calendar cal8;
-
@AfterEach
public void afterEachResetTimeZones() {
TimeZone.setDefault(TIME_ZONE_DEFAULT);
dateTimeParser.setTimeZone(TIME_ZONE_DEFAULT);
}
-
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) {
final GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
@@ -240,7 +242,6 @@ private void assertDate(final Date date, final int year, final int month, final
assertEquals(sec, cal.get(Calendar.SECOND));
assertEquals(mil, cal.get(Calendar.MILLISECOND));
}
-
@BeforeEach
public void setUp() throws Exception {
dateParser = new SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH);
@@ -1303,10 +1304,34 @@ void testToCalendarWithTimeZoneNull() {
assertNullPointerException(() -> DateUtils.toCalendar(date1, null));
}
+ @ParameterizedTest
+ @MethodSource("testToLocalDateTimeTimeZone")
+ void testToLocalDateTime(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
+ assertEquals(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), DateUtils.toLocalDateTime(date));
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void testToLocalDateTimeTimeZone(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
+ assertEquals(expected, DateUtils.toLocalDateTime(date, timeZone));
+ }
+
+ @ParameterizedTest
+ @MethodSource("testToLocalDateTimeTimeZone")
+ void testToOffsetDateTime(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
+ assertEquals(OffsetDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), DateUtils.toOffsetDateTime(date));
+ }
+
+ @ParameterizedTest
+ @MethodSource("testToLocalDateTimeTimeZone")
+ void testToOffsetDateTimeTimeZone(final LocalDateTime expected, final Date date, final TimeZone timeZone) {
+ assertEquals(expected, DateUtils.toOffsetDateTime(date, timeZone).toLocalDateTime());
+ }
+
/**
- * Tests various values with the trunc method
+ * Tests various values with the trunc method.
*
- * @throws Exception so we don't have to catch it
+ * @throws Exception so we don't have to catch it.
*/
@Test
void testTruncate() throws Exception {