Skip to content

Commit

Permalink
DateUtilities.parse() now allows for timezone offsets to include a "s…
Browse files Browse the repository at this point in the history
…econds" (third) time component.

Many more conversion tests added.  682 conversions supported, 164 conversion pairs to test.
  • Loading branch information
jdereg committed Mar 4, 2024
1 parent 54b72be commit 220f1cb
Show file tree
Hide file tree
Showing 14 changed files with 306 additions and 96 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ The classes in the`.jar`file are version 52 (`JDK 1.8`).
To include in your project:
##### GradleF
```
implementation 'com.cedarsoftware:java-util:2.4.2'
implementation 'com.cedarsoftware:java-util:2.4.3'
```

##### Maven
```
<dependency>
<groupId>com.cedarsoftware</groupId>
<artifactId>java-util</artifactId>
<version>2.4.2</version>
<version>2.4.3</version>
</dependency>
```
---
Expand Down
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
### Revision History
* 2.4.3
* `Converter` - many more tests added. Up to about 680 combinations now. Waiting to release 2.5.0 when all "cross product" of tests are completed.
* 2.4.2
* Fixed compatibility issues with `StringUtilities.` Method parameters changed from String to CharSequence broke backward compatibility. Linked jars are bound to method signature at compile time, not at runtime. Added both methods where needed. Removed methods with "Not" in the name.
* Fixed compatibility issue with `FastByteArrayOutputStream.` The `.getBuffer()` API was removed in favor of toByteArray(). Now both methods exist, leaving `getBuffer()` for backward compatibility.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<groupId>com.cedarsoftware</groupId>
<artifactId>java-util</artifactId>
<packaging>jar</packaging>
<version>2.4.2</version>
<version>2.4.3</version>
<description>Java Utilities</description>
<url>https://github.com/jdereg/java-util</url>

Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/cedarsoftware/util/ArrayUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public final class ArrayUtilities

public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
public static final char[] EMPTY_CHAR_ARRAY = new char[0];
public static final Character[] EMPTY_CHARACTER_ARRAY = new Character[0];

public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];

Expand Down
25 changes: 13 additions & 12 deletions src/main/java/com/cedarsoftware/util/DateUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
Expand Down Expand Up @@ -91,6 +90,7 @@ public final class DateUtilities {
private static final String wsOrComma = "[ ,]+";
private static final String tzUnix = "[A-Z]{1,3}";
private static final String tz_Hh_MM = "[+-]\\d{1,2}:\\d{2}";
private static final String tz_Hh_MM_SS = "[+-]\\d{1,2}:\\d{2}:\\d{2}";
private static final String tz_HHMM = "[+-]\\d{4}";
private static final String tz_Hh = "[+-]\\d{1,2}";
private static final String tzNamed = wsOp + "\\[?[A-Za-z][A-Za-z0-9~\\/._+-]+]?";
Expand All @@ -112,7 +112,7 @@ public final class DateUtilities {
Pattern.CASE_INSENSITIVE);

private static final Pattern timePattern = Pattern.compile(
"(" + d2 + "):(" + d2 + ")(?::(" + d2 + ")(" + nano + ")?)?(" + tz_Hh_MM + "|" + tz_HHMM + "|" + tz_Hh + "|Z)?(" + tzNamed + ")?",
"(" + d2 + "):(" + d2 + ")(?::(" + d2 + ")(" + nano + ")?)?(" + tz_Hh_MM_SS + "|" + tz_Hh_MM + "|" + tz_HHMM + "|" + tz_Hh + "|Z)?(" + tzNamed + ")?",
Pattern.CASE_INSENSITIVE);

private static final Pattern dayPattern = Pattern.compile("\\b(" + days + ")\\b", Pattern.CASE_INSENSITIVE);
Expand Down Expand Up @@ -155,32 +155,33 @@ private DateUtilities() {
* timezone used when one is not specified.
* @param dateStr String containing a date. If there is excess content, it will throw an IllegalArgumentException.
* @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. If a null or empty String is
* 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) {
if (StringUtilities.isWhitespace(dateStr)) {
if (StringUtilities.isEmpty(dateStr)) {
return null;
}
Instant instant;
TemporalAccessor dateTime = parseDate(dateStr, ZoneId.systemDefault(), true);
ZonedDateTime dateTime = parseDate(dateStr, ZoneId.systemDefault(), true);
instant = Instant.from(dateTime);
Date date = Date.from(instant);
return date;
return Date.from(instant);
}

/**
* Main API. Retrieve date-time from passed in String. The boolean ensureDateTimeAlone, if set true, ensures that
* no other non-date content existed in the String.
* @param dateStr String containing a date. See DateUtilities class Javadoc for all the supported formats. Cannot
* be null or empty String.
* @param dateStr String containing a date. See DateUtilities class Javadoc for all the supported formats.
* @param defaultZoneId ZoneId to use if no timezone offset or name is given. Cannot be null.
* @param ensureDateTimeAlone If true, if there is excess non-Date content, it will throw an IllegalArgument exception.
* @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.
* 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 ZonedDateTime parseDate(String dateStr, ZoneId defaultZoneId, boolean ensureDateTimeAlone) {
Convention.throwIfNullOrEmpty(dateStr, "'dateStr' must not be null or empty String.");
if (StringUtilities.isEmpty(dateStr)) {
return null;
}
Convention.throwIfNull(defaultZoneId, "ZoneId cannot be null. Use ZoneId.of(\"America/New_York\"), ZoneId.systemDefault(), etc.");
dateStr = dateStr.trim();

Expand Down Expand Up @@ -355,7 +356,7 @@ private static void verifyNoGarbageLeft(String remnant) {
if (StringUtilities.length(remnant) > 0) {
remnant = remnant.replaceAll("T|,", "").trim();
if (!remnant.isEmpty()) {
throw new IllegalArgumentException("Issue parsing date-time, other characters present: " + remnant);
throw new IllegalArgumentException("Issue parsing date-time, other characters present: " + remnant);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ static LocalTime toLocalTime(Object from, Converter converter) {
BigDecimal nanos = seconds.multiply(BILLION);
try {
return LocalTime.ofNanoOfDay(nanos.longValue());
}
catch (Exception e) {
} catch (Exception e) {
throw new IllegalArgumentException("Input value [" + seconds.toPlainString() + "] for conversion to LocalTime must be >= 0 && <= 86399.999999999", e);
}
}
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/com/cedarsoftware/util/convert/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,6 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(String.class, String.class), Converter::identity);
CONVERSION_DB.put(pair(Duration.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(Instant.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(LocalTime.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(MonthDay.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(YearMonth.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(Period.class, String.class), StringConversions::toString);
Expand Down Expand Up @@ -836,7 +835,6 @@ private static void buildFactoryConversions() {

// toCharArray
CONVERSION_DB.put(pair(Void.class, char[].class), VoidConversions::toNull);
CONVERSION_DB.put(pair(Void.class, Character[].class), VoidConversions::toNull);
CONVERSION_DB.put(pair(String.class, char[].class), StringConversions::toCharArray);
CONVERSION_DB.put(pair(StringBuilder.class, char[].class), StringConversions::toCharArray);
CONVERSION_DB.put(pair(StringBuffer.class, char[].class), StringConversions::toCharArray);
Expand All @@ -845,6 +843,12 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(char[].class, char[].class), CharArrayConversions::toCharArray);
CONVERSION_DB.put(pair(byte[].class, char[].class), ByteArrayConversions::toCharArray);

// toCharacterArray
CONVERSION_DB.put(pair(Void.class, Character[].class), VoidConversions::toNull);
CONVERSION_DB.put(pair(String.class, Character[].class), StringConversions::toCharacterArray);
CONVERSION_DB.put(pair(StringBuffer.class, Character[].class), StringConversions::toCharacterArray);
CONVERSION_DB.put(pair(StringBuilder.class, Character[].class), StringConversions::toCharacterArray);

// toCharBuffer
CONVERSION_DB.put(pair(Void.class, CharBuffer.class), VoidConversions::toNull);
CONVERSION_DB.put(pair(String.class, CharBuffer.class), StringConversions::toCharBuffer);
Expand Down Expand Up @@ -888,7 +892,7 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(AtomicBoolean.class, Map.class), MapConversions::initMap);
CONVERSION_DB.put(pair(AtomicInteger.class, Map.class), MapConversions::initMap);
CONVERSION_DB.put(pair(AtomicLong.class, Map.class), MapConversions::initMap);
CONVERSION_DB.put(pair(Date.class, Map.class), MapConversions::initMap);
CONVERSION_DB.put(pair(Date.class, Map.class), DateConversions::toMap);
CONVERSION_DB.put(pair(java.sql.Date.class, Map.class), MapConversions::initMap);
CONVERSION_DB.put(pair(Timestamp.class, Map.class), MapConversions::initMap);
CONVERSION_DB.put(pair(LocalDate.class, Map.class), MapConversions::initMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@
import java.time.format.DateTimeFormatterBuilder;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import com.cedarsoftware.util.CompactLinkedMap;

import static com.cedarsoftware.util.convert.Converter.VALUE;

/**
* @author Kenny Partlow ([email protected])
* <br>
Expand Down Expand Up @@ -91,7 +96,13 @@ static LocalDate toLocalDate(Object from, Converter converter) {
}

static LocalTime toLocalTime(Object from, Converter converter) {
return toZonedDateTime(from, converter).toLocalTime();
Instant instant = toInstant(from, converter);

// Convert Instant to LocalDateTime
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, converter.getOptions().getZoneId());

// Extract the LocalTime from LocalDateTime
return localDateTime.toLocalTime();
}

static BigInteger toBigInteger(Object from, Converter converter) {
Expand Down Expand Up @@ -131,4 +142,11 @@ static String toString(Object from, Converter converter) {

return zonedDateTime.format(formatter);
}

static Map<String, Object> toMap(Object from, Converter converter) {
Date date = (Date) from;
Map<String, Object> map = new CompactLinkedMap<>();
map.put(VALUE, date.getTime());
return map;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ final class MapConversions {
static final String MINUTES = "minutes";
static final String SECOND = "second";
static final String SECONDS = "seconds";
static final String EPOCH_MILLIS = "epochMillis";
static final String MILLI_SECONDS = "millis";
static final String NANO = "nano";
static final String NANOS = "nanos";
Expand Down Expand Up @@ -176,7 +177,7 @@ static java.sql.Date toSqlDate(Object from, Converter converter) {
}

static Date toDate(Object from, Converter converter) {
return fromSingleKey(from, converter, TIME, Date.class);
return fromSingleKey(from, converter, EPOCH_MILLIS, Date.class);
}

private static final String[] TIMESTAMP_PARAMS = new String[] { TIME, NANOS };
Expand Down
Loading

0 comments on commit 220f1cb

Please sign in to comment.