Skip to content

Commit

Permalink
Change internals of DateUtilities to use ZonedDateTime instead of Cal…
Browse files Browse the repository at this point in the history
…endar
  • Loading branch information
jdereg committed Jan 22, 2024
1 parent 9cd01bc commit 412de58
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 46 deletions.
74 changes: 29 additions & 45 deletions src/main/java/com/cedarsoftware/util/DateUtilities.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.cedarsoftware.util;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
Expand Down Expand Up @@ -155,32 +156,31 @@ private DateUtilities() {
* Main API. Retrieve date-time from passed in String.
* @param dateStr String containing a date. If there is excess content, it will be ignored.
* @return Date instance that represents the passed in date. See comments at top of class for supported
* formats. This API is intended to be super flexible in terms of what it can parse.
* formats. This API is intended to be super flexible in terms of what it can parse. If a null or empty String is
* passed in, null will be returned.
*/
public static Date parseDate(String dateStr) {
return parseDate(dateStr, false);
if (StringUtilities.isEmpty(dateStr)) {
return null;
}
ZonedDateTime zonedDateTime = parseDate(dateStr, false);
return new Date(zonedDateTime.toInstant().toEpochMilli());
}

/**
* Main API. Retrieve date-time from passed in String. The boolean enSureSoloDate, if set true, ensures that
* no other non-date content existed in the String. That requires additional time to verify.
* @param dateStr String containing a date.
* @param dateStr String containing a date. See DateUtilities class Javadoc for all the supported formats.
* @param ensureSoloDate If true, if there is excess non-Date content, it will throw an IllegalArgument exception.
* @return Date instance that represents the passed in date. See comments at top of class for supported
* formats. This API is intended to be super flexible in terms of what it can parse.
* @return ZonedDateTime instance converted from the passed in date String. See comments at top of class for supported
* formats. This API is intended to be super flexible in terms of what it can parse.
*/
public static Date parseDate(String dateStr, boolean ensureSoloDate) {
if (dateStr == null) {
return null;
}

public static ZonedDateTime parseDate(String dateStr, boolean ensureSoloDate) {
Convention.throwIfNullOrEmpty(dateStr, "dateString must not be null or empty String.");
dateStr = dateStr.trim();
if (dateStr.isEmpty()) {
return null;
}

if (allDigits.matcher(dateStr).matches()) {
return parseEpochString(dateStr);
return Instant.ofEpochMilli(Long.parseLong(dateStr)).atZone(ZoneId.of("UTC"));
}

String year, day, remains, tz = null;
Expand Down Expand Up @@ -264,13 +264,13 @@ public static Date parseDate(String dateStr, boolean ensureSoloDate) {
}

// Set Timezone into Calendar
Calendar c = initCalendar(tz);

return getDate(dateStr, c, noTime, year, month, day, hour, min, sec, milli);
ZoneId zoneId = getTimeZone(tz);
ZonedDateTime zonedDateTime = getDate(dateStr, zoneId, noTime, year, month, day, hour, min, sec, milli);
return zonedDateTime;
}

private static Date getDate(String dateStr,
Calendar c,
private static ZonedDateTime getDate(String dateStr,
ZoneId zoneId,
boolean noTime,
String year,
int month,
Expand All @@ -281,18 +281,17 @@ private static Date getDate(String dateStr,
String milli) {
// Build Calendar from date, time, and timezone components, and retrieve Date instance from Calendar.
int y = Integer.parseInt(year);
int m = month - 1; // months are 0-based
int d = Integer.parseInt(day);

if (m < 0 || m > 11) {
if (month < 1 || month > 12) {
throw new IllegalArgumentException("Month must be between 1 and 12 inclusive, date: " + dateStr);
}
if (d < 1 || d > 31) {
throw new IllegalArgumentException("Day must be between 1 and 31 inclusive, date: " + dateStr);
}

if (noTime) { // no [valid] time portion
c.set(y, m, d);
return ZonedDateTime.of(y, month, d, 0, 0, 0, 0, zoneId);
} else {
// Regex prevents these from ever failing to parse.
int h = Integer.parseInt(hour);
Expand All @@ -310,38 +309,28 @@ private static Date getDate(String dateStr,
throw new IllegalArgumentException("Second must be between 0 and 59 inclusive, time: " + dateStr);
}

// regex enforces millis to number
c.set(y, m, d, h, mn, s);
c.set(Calendar.MILLISECOND, ms);
return ZonedDateTime.of(y, month, d, h, mn, s, ms * 1000 * 1000, zoneId);
}
return c.getTime();
}

private static Calendar initCalendar(String tz) {
Calendar c = Calendar.getInstance();
private static ZoneId getTimeZone(String tz) {
if (tz != null) {
if (tz.startsWith("-") || tz.startsWith("+")) {
ZoneOffset offset = ZoneOffset.of(tz);
ZoneId zoneId = ZoneId.ofOffset("GMT", offset);
TimeZone timeZone = TimeZone.getTimeZone(zoneId);
c.setTimeZone(timeZone);
return ZoneId.ofOffset("GMT", offset);
} else {
try {
ZoneId zoneId = ZoneId.of(tz);
TimeZone timeZone = TimeZone.getTimeZone(zoneId);
c.setTimeZone(timeZone);
return ZoneId.of(tz);
} catch (Exception e) {
TimeZone timeZone = TimeZone.getTimeZone(tz);
if (timeZone.getRawOffset() != 0) {
c.setTimeZone(timeZone);
} else {
if (timeZone.getRawOffset() == 0) {
throw e;
}
return timeZone.toZoneId();
}
}
}
c.clear();
return c;
return ZoneId.systemDefault();
}

private static void verifyNoGarbageLeft(String remnant) {
Expand Down Expand Up @@ -394,9 +383,4 @@ private static String prepareMillis(String milli) {
return milli.substring(0, 3);
}
}

private static Date parseEpochString(String dateStr) {
long num = Long.parseLong(dateStr);
return new Date(num);
}
}
3 changes: 2 additions & 1 deletion src/test/java/com/cedarsoftware/util/TestDateUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
Expand Down Expand Up @@ -346,7 +347,7 @@ void testDayOfWeek()
DateUtilities.parseDate(" Dec 25, 2014, thursday ");
}
try {
Date date = DateUtilities.parseDate("text Dec 25, 2014", true);
ZonedDateTime date = DateUtilities.parseDate("text Dec 25, 2014", true);
fail();
} catch (Exception ignored) { }

Expand Down

0 comments on commit 412de58

Please sign in to comment.