Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/main/java/org/threeten/extra/Interval.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ private static Interval parseSplit(CharSequence startStr, CharSequence endStr) {
}
}
// instant followed by instant or duration
if (isUnbounded(startStr)) {
return parseEndDateTime(Instant.MIN, ZoneOffset.UTC, endStr);
}
OffsetDateTime start;
try {
start = OffsetDateTime.parse(startStr);
Expand All @@ -199,6 +202,10 @@ private static Interval parseSplit(CharSequence startStr, CharSequence endStr) {
return parseEndDateTime(start.toInstant(), start.getOffset(), endStr);
}

private static boolean isUnbounded(CharSequence sequence) {
return sequence.length() == 2 && sequence.charAt(0) == '.' && sequence.charAt(1) == '.';
}

// handle case where Instant is outside the bounds of OffsetDateTime
private static Interval parseStartExtended(CharSequence startStr, CharSequence endStr) {
Instant start = Instant.parse(startStr);
Expand All @@ -219,6 +226,10 @@ private static Interval parseStartExtended(CharSequence startStr, CharSequence e

// parse when there are two date-times
private static Interval parseEndDateTime(Instant start, ZoneOffset offset, CharSequence endStr) {
if (isUnbounded(endStr)) {
return Interval.of(start, Instant.MAX);
}

try {
TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest(endStr, OffsetDateTime::from, LocalDateTime::from);
if (temporal instanceof OffsetDateTime) {
Expand Down Expand Up @@ -708,13 +719,15 @@ public int hashCode() {
* <p>
* The output will be the ISO-8601 format formed by combining the
* {@code toString()} methods of the two instants, separated by a forward slash.
* Unbounded intervals will have its open end represented by two periods, as in
* {@code 2007-12-03T10:15:30/..}.
*
* @return a string representation of this instant, not null
* @return a string representation of this interval, not null
*/
@Override
@ToString
public String toString() {
return start.toString() + '/' + end.toString();
return (isUnboundedStart() ? ".." : getStart()) + "/" + (isUnboundedEnd() ? ".." : getEnd());
}

}
33 changes: 31 additions & 2 deletions src/test/java/org/threeten/extra/TestInterval.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,11 @@ public static Object[][] data_parseValid() {
{NOW1.atOffset(ZoneOffset.ofHours(2)) + "/" + NOW2.atOffset(ZoneOffset.ofHours(2)).toLocalDateTime(), NOW1, NOW2},
{MIN_OFFSET_DATE_TIME.toString() + "/" + MAX_OFFSET_DATE_TIME, MIN_OFFSET_DATE_TIME, MAX_OFFSET_DATE_TIME},
{NOW1 + "/" + Instant.MAX, NOW1, Instant.MAX},
{Instant.MIN.toString() + "/" + NOW2, Instant.MIN, NOW2},
{Instant.MIN.toString() + "/" + Instant.MAX, Instant.MIN, Instant.MAX}
{Instant.MIN + "/" + NOW2, Instant.MIN, NOW2},
{Instant.MIN + "/" + Instant.MAX, Instant.MIN, Instant.MAX},
{"../" + NOW2, Instant.MIN, NOW2},
{NOW1 + "/..", NOW1, Instant.MAX},
{"../..", Instant.MIN, Instant.MAX}
};
}

Expand All @@ -214,6 +217,16 @@ public void test_parse_CharSequence_badOrder() {
assertThrows(DateTimeException.class, () -> Interval.parse(NOW2 + "/" + NOW1));
}

@Test
public void test_parse_CharSequence_illegalOpenStartDuration() {
assertThrows(DateTimeException.class, () -> Interval.parse("../PT1H"));
}

@Test
public void test_parse_CharSequence_illegalDurationOpenEnd() {
assertThrows(DateTimeException.class, () -> Interval.parse("PT1H/.."));
}

@Test
public void test_parse_CharSequence_badFormat() {
assertThrows(DateTimeParseException.class, () -> Interval.parse(NOW2 + "-" + NOW1));
Expand Down Expand Up @@ -843,4 +856,20 @@ public void test_toString() {
assertEquals(NOW1 + "/" + NOW2, test.toString());
}

@Test
public void test_toString_open_end() {
Interval test = Interval.ALL.withStart(NOW1);
assertEquals(NOW1 + "/..", test.toString());
}
@Test
public void test_toString_open_start() {
Interval test = Interval.ALL.withEnd(NOW2);
assertEquals("../" + NOW2, test.toString());
}
@Test
public void test_toString_open_all() {
Interval test = Interval.ALL;
assertEquals("../..", test.toString());
}

}