Skip to content

Commit

Permalink
Business rule update - DateUtilities.parseDate(number as String) will…
Browse files Browse the repository at this point in the history
… be considered to be epoch millis always.
  • Loading branch information
jdereg committed Jan 20, 2024
1 parent a8d8014 commit c4f96f6
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 101 deletions.
37 changes: 10 additions & 27 deletions src/main/java/com/cedarsoftware/util/DateUtilities.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.cedarsoftware.util;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
Expand All @@ -17,9 +15,9 @@
* may be inconsistent. This will parse the following formats (constrained only by java.util.Date limitations...best
* time resolution is milliseconds):<br/>
* <pre>
* 12-31-2023 -or- 12/31/2023 mm is 1-12 or 01-12, dd is 1-31 or 01-31, and yyyy can be 0000 to 9999.
* 12-31-2023, 12/31/2023, 12.31.2023 mm is 1-12 or 01-12, dd is 1-31 or 01-31, and yyyy can be 0000 to 9999.
*
* 2023-12-31 -or- 2023/12/31 mm is 1-12 or 01-12, dd is 1-31 or 01-31, and yyyy can be 0000 to 9999.
* 2023-12-31, 2023/12/31, 2023.12.31 mm is 1-12 or 01-12, dd is 1-31 or 01-31, and yyyy can be 0000 to 9999.
*
* January 6th, 2024 Month (3-4 digit abbreviation or full English name), white-space and optional comma,
* day of month (1-31 or 0-31) with optional suffixes 1st, 3rd, 22nd, whitespace and
Expand All @@ -44,8 +42,7 @@
* hh:mm:ss hours (00-23), minutes (00-59), seconds (00-59). 24 hour format.
*
* hh:mm:ss.sssss hh:mm:ss and fractional seconds. Variable fractional seconds supported. Date only
* supports up to millisecond precision, so anything after 3 decimal places is
* effectively ignored.
* supports up to millisecond precision, so anything after 3 decimal places is ignored.
*
* hh:mm:offset -or- offset can be specified as +HH:mm, +HHmm, +HH, -HH:mm, -HHmm, -HH, or Z (GMT)
* hh:mm:ss.sss:offset which will match: "12:34", "12:34:56", "12:34.789", "12:34:56.789", "12:34+01:00",
Expand All @@ -55,20 +52,14 @@
* hh:mm:ss.sss:zone PST, IST, JST, BST etc. as well as the long forms: "America/New York", "Asia/Saigon",
* etc. See ZoneId.getAvailableZoneIds().
* </pre>
* DateUtilities will parse Epoch-based integer-based values. It supports the following 3 types:
* DateUtilities will parse Epoch-based integer-based value. It is considered number of milliseconds since Jan, 1970 GMT.
* <pre>
* "0" to "999999" A string of numeric digits from 0 to 6 in length will be parsed and returned as
* the number of days since the Unix Epoch, January 1st, 1970 00:00:00 UTC.
*
* "0000000" to "99999999999" A string of numeric digits from 7 to 11 in length will be parsed and returned as
* the number of seconds since the Unix Epoch, January 1st, 1970 00:00:00 UTC.
*
* "000000000000" to A string of numeric digits from 12 to 18 in length will be parsed and returned as
* "999999999999999999" the number of milli-seconds since the Unix Epoch, January 1st, 1970 00:00:00 UTC.
* "0" to A string of numeric digits will be parsed and returned as the number of milliseconds
* "999999999999999999" the Unix Epoch, January 1st, 1970 00:00:00 UTC.
* </pre>
* On all patterns above (excluding the numeric epoch days, seconds, millis), if a day-of-week (e.g. Thu, Sunday, etc.)
* is included (front, back, or between date and time), it will be ignored, allowing for even more formats than what is
* listed here. The day-of-week is not be used to influence the Date calculation.
* On all patterns above (excluding the numeric epoch millis), if a day-of-week (e.g. Thu, Sunday, etc.) is included
* (front, back, or between date and time), it will be ignored, allowing for even more formats than listed here.
* The day-of-week is not be used to influence the Date calculation.
*
* @author John DeRegnaucourt ([email protected])
* <br>
Expand Down Expand Up @@ -350,14 +341,6 @@ private static String prepareMillis(String milli) {

private static Date parseEpochString(String dateStr) {
long num = Long.parseLong(dateStr);
if (dateStr.length() < 7) { // days since epoch (good until 4707-11-28 00:00:00)
Instant instant = LocalDate.ofEpochDay(num).atStartOfDay(ZoneId.of("GMT")).toInstant();
return new Date(instant.toEpochMilli());
} else if (dateStr.length() < 12) { // seconds since epoch (good until 5138-11-16 09:46:39)
Instant instant = Instant.ofEpochSecond(num);
return new Date(instant.toEpochMilli());
} else { // millis since epoch (good until 31690708-07-05 01:46:39.999)
return new Date(num);
}
return new Date(num);
}
}
51 changes: 1 addition & 50 deletions src/test/java/com/cedarsoftware/util/TestDateUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -730,56 +730,7 @@ void testBadTimeSeparators()
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Issue parsing data/time, other characters present: 12-49-58");
}

@Test
void testEpochDays()
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

// 6 digits - 0 case
Date date = DateUtilities.parseDate("000000");
String gmtDateString = sdf.format(date);
assertEquals("1970-01-01 00:00:00", gmtDateString);

// 6 digits - 1 past zero case (increments by a day)
date = DateUtilities.parseDate("000001");
gmtDateString = sdf.format(date);
assertEquals("1970-01-02 00:00:00", gmtDateString);

// 6-digits - max case - all 9's
date = DateUtilities.parseDate("999999");
gmtDateString = sdf.format(date);
assertEquals("4707-11-28 00:00:00", gmtDateString);
}

@Test
void testEpochSeconds()
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

// Strings 7 digits to 12 digits are treated as seconds since unix epoch
Date date = DateUtilities.parseDate("0000000");
String gmtDateString = sdf.format(date);
assertEquals("1970-01-01 00:00:00", gmtDateString);

// 7 digits, 1 past the 0 case
date = DateUtilities.parseDate("0000001");
gmtDateString = sdf.format(date);
assertEquals("1970-01-01 00:00:01", gmtDateString);

// 11 digits, 1 past the 0 case
date = DateUtilities.parseDate("00000000001");
gmtDateString = sdf.format(date);
assertEquals("1970-01-01 00:00:01", gmtDateString);

// 11 digits, max case - all 9's
date = DateUtilities.parseDate("99999999999");
gmtDateString = sdf.format(date);
assertEquals("5138-11-16 09:46:39", gmtDateString);
}


@Test
void testEpochMillis()
{
Expand Down
46 changes: 22 additions & 24 deletions src/test/java/com/cedarsoftware/util/convert/ConverterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

Expand Down Expand Up @@ -1339,26 +1338,26 @@ void testLocalDateToOthers()
@Test
void testStringToLocalDate()
{
String dec23rd2023 = "19714";
LocalDate ld = this.converter.convert(dec23rd2023, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
// assert ld.getDayOfMonth() == 23;
String testDate = "1705769204092";
LocalDate ld = this.converter.convert(testDate, LocalDate.class);
assert ld.getYear() == 2024;
assert ld.getMonthValue() == 1;
assert ld.getDayOfMonth() == 20;

dec23rd2023 = "2023-12-23";
ld = this.converter.convert(dec23rd2023, LocalDate.class);
testDate = "2023-12-23";
ld = this.converter.convert(testDate, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
assert ld.getDayOfMonth() == 23;

dec23rd2023 = "2023/12/23";
ld = this.converter.convert(dec23rd2023, LocalDate.class);
testDate = "2023/12/23";
ld = this.converter.convert(testDate, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
assert ld.getDayOfMonth() == 23;

dec23rd2023 = "12/23/2023";
ld = this.converter.convert(dec23rd2023, LocalDate.class);
testDate = "12/23/2023";
ld = this.converter.convert(testDate, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
assert ld.getDayOfMonth() == 23;
Expand All @@ -1368,30 +1367,29 @@ void testStringToLocalDate()
void testStringOnMapToLocalDate()
{
Map<String, Object> map = new HashMap<>();
String dec23Epoch = "19714";
map.put("value", dec23Epoch);
String testDate = "1705769204092";
map.put("value", testDate);
LocalDate ld = this.converter.convert(map, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
// assert ld.getDayOfMonth() == 23;

assert ld.getYear() == 2024;
assert ld.getMonthValue() == 1;
assert ld.getDayOfMonth() == 20;

dec23Epoch = "2023-12-23";
map.put("value", dec23Epoch);
testDate = "2023-12-23";
map.put("value", testDate);
ld = this.converter.convert(map, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
assert ld.getDayOfMonth() == 23;

dec23Epoch = "2023/12/23";
map.put("value", dec23Epoch);
testDate = "2023/12/23";
map.put("value", testDate);
ld = this.converter.convert(map, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
assert ld.getDayOfMonth() == 23;

dec23Epoch = "12/23/2023";
map.put("value", dec23Epoch);
testDate = "12/23/2023";
map.put("value", testDate);
ld = this.converter.convert(map, LocalDate.class);
assert ld.getYear() == 2023;
assert ld.getMonthValue() == 12;
Expand Down

0 comments on commit c4f96f6

Please sign in to comment.