Skip to content

Commit 07fb413

Browse files
committed
Add Date to LocalDateTime conversion methods and test cases
This commit enhances the DateUtils class by adding two new methods to convert java.util.Date to java.time.LocalDateTime, supporting both default and specified time zones. The implementation leverages Java 8's date-time API for accurate time zone handling, including: - `toLocalDateTime(Date date)`: Uses the system's default time zone - `toLocalDateTime(Date date, TimeZone tz)`: Explicitly specifies time zone via TimeZone parameter Key improvements: - Proper null checking with Objects.requireNonNull() - Direct conversion via Instant and ZoneId for timezone accuracy - Maintains parity with existing DateUtils method naming conventions Test cases added in DateUtilsTest: - Default time zone conversion (Asia/Shanghai example) - Specified time zone conversion (America/New_York) - Null input validation (throws NullPointerException) - Daylight saving time handling (America/New_York DST case) - Extreme time zone test (Pacific/Kiritimati, UTC+14) These changes enable seamless integration between legacy Date APIs and modern LocalDateTime, while ensuring robust timezone handling across different environments.
1 parent 4650d39 commit 07fb413

2 files changed

Lines changed: 89 additions & 0 deletions

File tree

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.text.ParseException;
2020
import java.text.ParsePosition;
21+
import java.time.LocalDateTime;
22+
import java.time.ZoneId;
2123
import java.util.Calendar;
2224
import java.util.Date;
2325
import java.util.Iterator;
@@ -1625,6 +1627,29 @@ public static Calendar toCalendar(final Date date, final TimeZone tz) {
16251627
return c;
16261628
}
16271629

1630+
/**
1631+
* Converts a {@link Date} into a {@link LocalDateTime}, using the default time zone.
1632+
* @param date the date to convert to a LocalDateTime
1633+
* @return the created LocalDateTime
1634+
* @throws NullPointerException if {@code date} is null
1635+
* @since 3.18
1636+
*/
1637+
public static LocalDateTime toLocalDateTime(final Date date) {
1638+
return toLocalDateTime(date, TimeZone.getDefault());
1639+
}
1640+
1641+
/**
1642+
* Converts a {@link Date} into a {@link LocalDateTime}
1643+
* @param date the date to convert to a LocalDateTime
1644+
* @param tz the time zone of the {@code date}
1645+
* @return the created LocalDateTime
1646+
* @throws NullPointerException if {@code date} is null
1647+
* @since 3.18
1648+
*/
1649+
public static LocalDateTime toLocalDateTime(final Date date, final TimeZone tz) {
1650+
return Objects.requireNonNull(date, "date").toInstant().atZone(ZoneId.of(tz.getID())).toLocalDateTime();
1651+
}
1652+
16281653
/**
16291654
* Truncates a date, leaving the field specified as the most
16301655
* significant field.

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
import java.text.DateFormat;
2929
import java.text.ParseException;
3030
import java.text.SimpleDateFormat;
31+
import java.time.Instant;
32+
import java.time.LocalDateTime;
33+
import java.time.ZoneOffset;
3134
import java.util.Calendar;
3235
import java.util.Date;
3336
import java.util.GregorianCalendar;
@@ -1285,6 +1288,67 @@ public void testToCalendarWithTimeZoneNull() {
12851288
assertThrows(NullPointerException.class, () -> DateUtils.toCalendar(date1, null));
12861289
}
12871290

1291+
@Test
1292+
void shouldConvertDateToLocalDateTimeUsingDefaultTimeZone() {
1293+
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
1294+
1295+
Instant instant = LocalDateTime.of(2023, 1, 1, 0, 0)
1296+
.atOffset(ZoneOffset.UTC)
1297+
.toInstant();
1298+
Date date = Date.from(instant);
1299+
1300+
LocalDateTime expected = LocalDateTime.of(2023, 1, 1, 8, 0);
1301+
1302+
assertEquals(expected, DateUtils.toLocalDateTime(date));
1303+
}
1304+
1305+
@Test
1306+
void shouldConvertDateToLocalDateTimeUsingSpecifiedTimeZone() {
1307+
Instant instant = LocalDateTime.of(2023, 1, 1, 0, 0)
1308+
.atOffset(ZoneOffset.UTC)
1309+
.toInstant();
1310+
Date date = Date.from(instant);
1311+
1312+
TimeZone newYorkTimeZone = TimeZone.getTimeZone("America/New_York");
1313+
LocalDateTime expected = LocalDateTime.of(2022, 12, 31, 19, 0);
1314+
1315+
assertEquals(expected, DateUtils.toLocalDateTime(date, newYorkTimeZone));
1316+
}
1317+
1318+
@Test
1319+
void shouldThrowNullPointerExceptionWhenDateIsNull() {
1320+
assertThrows(NullPointerException.class, () -> DateUtils.toLocalDateTime(null));
1321+
assertThrows(NullPointerException.class, () -> DateUtils.toLocalDateTime(null, TimeZone.getDefault()));
1322+
}
1323+
1324+
@Test
1325+
void shouldHandleDaylightSavingTimeCorrectly() {
1326+
Instant instant = LocalDateTime.of(2023, 3, 12, 7, 0)
1327+
.atOffset(ZoneOffset.UTC)
1328+
.toInstant();
1329+
Date date = Date.from(instant);
1330+
1331+
TimeZone newYorkTimeZone = TimeZone.getTimeZone("America/New_York");
1332+
LocalDateTime expected = LocalDateTime.of(2023, 3, 12, 3, 0);
1333+
1334+
assertEquals(expected, DateUtils.toLocalDateTime(date, newYorkTimeZone));
1335+
}
1336+
1337+
@Test
1338+
void shouldHandleExtremeTimeZoneCorrectly() {
1339+
Instant instant = LocalDateTime.of(2023, 1, 1, 0, 0)
1340+
.atOffset(ZoneOffset.UTC)
1341+
.toInstant();
1342+
Date date = Date.from(instant);
1343+
1344+
TimeZone extremeTimeZone = TimeZone.getTimeZone("Pacific/Kiritimati");
1345+
LocalDateTime expected = LocalDateTime.of(2023, 1, 1, 14, 0);
1346+
1347+
assertEquals(expected, DateUtils.toLocalDateTime(date, extremeTimeZone));
1348+
}
1349+
1350+
1351+
12881352
/**
12891353
* Tests various values with the trunc method
12901354
*

0 commit comments

Comments
 (0)