diff --git a/src/main/java/com/cedarsoftware/util/DateUtilities.java b/src/main/java/com/cedarsoftware/util/DateUtilities.java index 9f6f195be..313580a6b 100644 --- a/src/main/java/com/cedarsoftware/util/DateUtilities.java +++ b/src/main/java/com/cedarsoftware/util/DateUtilities.java @@ -171,14 +171,16 @@ public static Date parseDate(String dateStr) { /** * 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. See DateUtilities class Javadoc for all the supported formats. - * @param defaultZoneId ZoneId to use if no timezone or timezone offset is given. + * @param dateStr String containing a date. See DateUtilities class Javadoc for all the supported formats. Cannot + * be null or empty String. + * @param defaultZoneId ZoneId to use if no timezone or timezone offset 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. */ public static ZonedDateTime parseDate(String dateStr, ZoneId defaultZoneId, boolean ensureDateTimeAlone) { Convention.throwIfNullOrEmpty(dateStr, "'dateStr' must not be null or empty String."); + Convention.throwIfNull(defaultZoneId, "ZoneId cannot be null. Use ZoneId.of(\"America/New_York\"), ZoneId.systemDefault(), etc."); dateStr = dateStr.trim(); if (allDigits.matcher(dateStr).matches()) { @@ -276,7 +278,7 @@ private static ZonedDateTime getDate(String dateStr, String hour, String min, String sec, - String milli) { + String nanos) { // Build Calendar from date, time, and timezone components, and retrieve Date instance from Calendar. int y = Integer.parseInt(year); int d = Integer.parseInt(day); @@ -295,7 +297,7 @@ private static ZonedDateTime getDate(String dateStr, int h = Integer.parseInt(hour); int mn = Integer.parseInt(min); int s = Integer.parseInt(sec); - int ms = Integer.parseInt(prepareMillis(milli)); // Must be between 0 and 999. + int ns = Integer.parseInt(nanos); if (h > 23) { throw new IllegalArgumentException("Hour must be between 0 and 23 inclusive, time: " + dateStr); @@ -307,7 +309,8 @@ private static ZonedDateTime getDate(String dateStr, throw new IllegalArgumentException("Second must be between 0 and 59 inclusive, time: " + dateStr); } - return ZonedDateTime.of(y, month, d, h, mn, s, ms * 1000 * 1000, zoneId); + ZonedDateTime zdt = ZonedDateTime.of(y, month, d, h, mn, s, ns, zoneId); + return zdt; } } @@ -364,21 +367,4 @@ private static String stripBrackets(String input) { } return input.replaceAll("^\\[|\\]$", ""); } - - /** - * Calendar & Date are only accurate to milliseconds. - */ - private static String prepareMillis(String milli) { - if (StringUtilities.isEmpty(milli)) { - return "000"; - } - final int len = milli.length(); - if (len == 1) { - return milli + "00"; - } else if (len == 2) { - return milli + "0"; - } else { - return milli.substring(0, 3); - } - } } \ No newline at end of file diff --git a/src/test/java/com/cedarsoftware/util/TestDateUtilities.java b/src/test/java/com/cedarsoftware/util/TestDateUtilities.java index bfef6ebdf..17ab965b3 100644 --- a/src/test/java/com/cedarsoftware/util/TestDateUtilities.java +++ b/src/test/java/com/cedarsoftware/util/TestDateUtilities.java @@ -890,4 +890,20 @@ void testTimeZoneParsing(String exampleZone, Long epochMilli) assertEquals(date2.toInstant().toEpochMilli(), epochMilli); } } + + @Test + void testTimeBetterThanMilliResolution() + { + ZonedDateTime zonedDateTime = DateUtilities.parseDate("Jan 22nd, 2024 21:52:05.123456789-05:00", ZoneId.systemDefault(), true); + assertEquals(123456789, zonedDateTime.getNano()); + assertEquals(2024, zonedDateTime.getYear()); + assertEquals(1, zonedDateTime.getMonthValue()); + assertEquals(22, zonedDateTime.getDayOfMonth()); + assertEquals(21, zonedDateTime.getHour()); + assertEquals(52, zonedDateTime.getMinute()); + assertEquals(5, zonedDateTime.getSecond()); + assertEquals(123456789, zonedDateTime.getNano()); + assertEquals(ZoneId.of("GMT-0500"), zonedDateTime.getZone()); + assertEquals(-60*60*5, zonedDateTime.getOffset().getTotalSeconds()); + } } \ No newline at end of file