Skip to content

Commit

Permalink
Support Optional String inputs
Browse files Browse the repository at this point in the history
DateTime has a an overridden constructor for Optional Strings.
Value field is an optional. An empty value string is represented
as "-".
  • Loading branch information
MerlinLim committed Oct 16, 2020
1 parent 85176db commit a2e73b4
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 16 deletions.
79 changes: 69 additions & 10 deletions src/main/java/seedu/address/model/util/DateTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,31 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Optional;

public class DateTime implements Comparable<DateTime> {
public static final String TIME_REGEX = "(([0-1]\\d)|(2[0-3])):([0-5]\\d)";
public static final String DATE_REGEX = "(([0-2]\\d)|(3[0-1]))-((0[1-9])|(1[0-2]))-(\\d{4})";
public static final String MESSAGE_CONSTRAINTS =
"From should be in the format of DD-MM-YYYY or DD-MM-YYYY HH:mm, and should not be blank."
+ "Note: Single digit month, day, and minute must start with a leading zero.";
"Dates should be in the format of DD-MM-YYYY or DD-MM-YYYY HH:mm, "
+ "and should not be blank. Note: Single digit month, day, and "
+ "minute must start with a leading zero.";

public static final String VALIDATION_REGEX = String.format("%s(\\s(%s))?",
DATE_REGEX, TIME_REGEX);

public static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormatter.ofPattern("dd-MM-yyyy[ HH:mm]");

public final LocalDateTime value;
public static final String EMPTY_DATETIME_VALUE_STRING = "-";

public final Optional<LocalDateTime> value;
public final String valueString;

/**
* Constructs a {@code date}.
*
* @param date A valid from.
* @param date A valid date.
*/
public DateTime(String date) {
requireNonNull(date);
Expand All @@ -39,11 +43,46 @@ public DateTime(String date) {
TemporalAccessor temporalAccessor = DATE_TIME_FORMATTER.parseBest(date,
LocalDateTime::from, LocalDate::from);
if (temporalAccessor instanceof LocalDateTime) {
this.value = (LocalDateTime) temporalAccessor;
this.valueString = this.value.format(DATE_TIME_FORMATTER);
LocalDateTime dateTimeParsed = (LocalDateTime) temporalAccessor;
this.value = Optional.of(dateTimeParsed);
this.valueString = dateTimeParsed.format(DATE_TIME_FORMATTER);
} else {
this.value = ((LocalDate) temporalAccessor).atStartOfDay();
this.valueString = ((LocalDate) temporalAccessor).format(DATE_TIME_FORMATTER);
LocalDate dateParsed = (LocalDate) temporalAccessor;
this.value = Optional.of((dateParsed).atStartOfDay());
this.valueString = dateParsed.format(DATE_TIME_FORMATTER);
}

}

/**
* Constructs a {@code date}.
*
* @param date A valid optional DateTime.
*/
public DateTime(Optional<String> date) {
// Check for constraints
date.ifPresent(d -> checkArgument(isValidDateTime(d), MESSAGE_CONSTRAINTS));

//Parse value
Optional<TemporalAccessor> temporalAccessor = date.map(d -> DATE_TIME_FORMATTER
.parseBest(d, LocalDateTime::from, LocalDate::from));
Optional<LocalDateTime> dateTimeParsed = temporalAccessor
.filter(t -> t instanceof LocalDateTime)
.map(t -> ((LocalDateTime) t));
Optional<LocalDate> dateParsed = temporalAccessor
.filter(t -> t instanceof LocalDate)
.map(t -> ((LocalDate) t));

if (dateTimeParsed.isPresent()) {
this.value = dateTimeParsed;
this.valueString = dateTimeParsed
.map(dt -> dt.format(DATE_TIME_FORMATTER))
.orElse(EMPTY_DATETIME_VALUE_STRING);
} else {
this.value = dateParsed.map(LocalDate::atStartOfDay);
this.valueString = dateParsed
.map(dt -> dt.format(DATE_TIME_FORMATTER))
.orElse(EMPTY_DATETIME_VALUE_STRING);
}

}
Expand All @@ -58,16 +97,36 @@ public static boolean isValidDateTime(String test) {
return test.matches(VALIDATION_REGEX);
}

/**
* Checks is DateTime exists.
*
* @return true if value in DateTime exists.
*/
public boolean isEmpty() {
return this.value.isEmpty();
}

@Override
public int compareTo(DateTime o) {
return this.value.compareTo(o.value);
if (value.isEmpty() && o.isEmpty()) {
return 0;
} else {
return this.value.map(v1 ->
o.value.map(v2-> v1.compareTo(v2)).orElse(-1))
.orElse(1);
}

}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof DateTime) // instanceof handles nulls
&& value.equals((((DateTime) other).value)); // state check
&& ((value.isEmpty() && ((DateTime) other).value.isEmpty()) //if v1 and v2 empty, return true
|| value.map(v1 -> ((DateTime) other)
.value.map(v2-> v1.equals(v2))
.orElse(false)) // if v2 not present, return false
.orElse(false)); // if v1 not present return false
}

@Override
Expand Down
33 changes: 27 additions & 6 deletions src/test/java/seedu/address/model/util/DateTimeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;
import java.util.Optional;

import org.junit.jupiter.api.Test;

class DateTimeTest {

Expand All @@ -31,32 +32,52 @@ void isValidDateTimeSuccess() {
@Test
void parseSuccess() {
DateTime dt = new DateTime(VALID_SAMPLE_A);
assertEquals(dt.toString(), VALID_SAMPLE_A);
assertEquals(VALID_SAMPLE_A, dt.toString());

DateTime dtNoTime = new DateTime(VALID_DATE_A);
assertEquals(dtNoTime.toString(), VALID_DATE_A);
assertEquals(VALID_DATE_A, dtNoTime.toString());

//Optional
dt = new DateTime(Optional.of(VALID_SAMPLE_A));
assertEquals(VALID_SAMPLE_A, dt.toString());

dtNoTime = new DateTime(Optional.of(VALID_DATE_A));
assertEquals(VALID_DATE_A, dtNoTime.toString());

//Optional Empty
assertEquals("-", new DateTime(Optional.empty()).toString());

}

@Test
void resolveOverflowParseSuccess() {

DateTime resolveA = new DateTime(VALID_SAMPLE_B);
assertEquals(resolveA.toString(), "30-11-2020 23:00");
assertEquals("30-11-2020 23:00", resolveA.toString());

DateTime resolveB = new DateTime(VALID_DATE_B);
assertEquals(resolveB.toString(), "29-02-2020");
assertEquals("29-02-2020", resolveB.toString());

DateTime resolveC = new DateTime(VALID_DATE_C);
assertEquals(resolveC.toString(), "28-02-2019");
assertEquals("28-02-2019", resolveC.toString());
}

@Test
void compareSuccess() {
DateTime a = new DateTime(VALID_SAMPLE_A);
DateTime b = new DateTime(VALID_SAMPLE_B);
DateTime c = new DateTime(VALID_DATE_A);
DateTime a1 = new DateTime(Optional.empty());
assertEquals(a.compareTo(b), -1);
assertEquals(a.compareTo(a), 0);
assertEquals(a.compareTo(c), 1);

//Compare Empty Optionals
//Empty Optionals have highest priority
assertEquals(a1.compareTo(a), 1);
assertEquals(a.compareTo(a1), -1);

//Both are Empty Optionals
assertEquals(a1.compareTo(a1), 0);
}
}

0 comments on commit a2e73b4

Please sign in to comment.