diff --git a/core/src/main/java/tech/tablesaw/api/DateTimeColumn.java b/core/src/main/java/tech/tablesaw/api/DateTimeColumn.java index a4756a2e4..dda749d97 100644 --- a/core/src/main/java/tech/tablesaw/api/DateTimeColumn.java +++ b/core/src/main/java/tech/tablesaw/api/DateTimeColumn.java @@ -221,18 +221,19 @@ public void setPrintFormatter(DateTimeColumnFormatter formatter) { /** {@inheritDoc} */ @Override public DateTimeColumn lag(int n) { + final int size = size(); int srcPos = n >= 0 ? 0 : -n; - long[] dest = new long[size()]; + long[] dest = new long[size]; int destPos = Math.max(n, 0); - int length = n >= 0 ? size() - n : size() + n; + int length = n >= 0 ? size - n : size + n; - for (int i = 0; i < size(); i++) { + for (int i = 0; i < size; i++) { dest[i] = DateTimeColumnType.missingValueIndicator(); } System.arraycopy(data.toLongArray(), srcPos, dest, destPos, length); - DateTimeColumn copy = emptyCopy(size()); + DateTimeColumn copy = emptyCopy(size); copy.data = new LongArrayList(dest); copy.setName(name() + " lag(" + n + ")"); return copy; diff --git a/core/src/main/java/tech/tablesaw/api/InstantColumn.java b/core/src/main/java/tech/tablesaw/api/InstantColumn.java index 971fd4953..63c909a46 100644 --- a/core/src/main/java/tech/tablesaw/api/InstantColumn.java +++ b/core/src/main/java/tech/tablesaw/api/InstantColumn.java @@ -46,10 +46,10 @@ import tech.tablesaw.columns.Column; import tech.tablesaw.columns.instant.InstantColumnFormatter; import tech.tablesaw.columns.instant.InstantColumnType; -import tech.tablesaw.columns.instant.InstantMapFunctions; import tech.tablesaw.columns.instant.PackedInstant; import tech.tablesaw.columns.temporal.TemporalFillers; import tech.tablesaw.columns.temporal.TemporalFilters; +import tech.tablesaw.columns.temporal.TemporalMapFunctions; import tech.tablesaw.selection.Selection; /** @@ -58,7 +58,7 @@ * instances of {@link java.time.Instant}, which have nanosecond precision */ public class InstantColumn extends AbstractColumn - implements InstantMapFunctions, + implements TemporalMapFunctions, TemporalFillers, TemporalFilters, CategoricalColumn { @@ -218,18 +218,19 @@ public void setPrintFormatter(InstantColumnFormatter formatter) { /** {@inheritDoc} */ @Override public InstantColumn lag(int n) { + final int size = size(); int srcPos = n >= 0 ? 0 : -n; - long[] dest = new long[size()]; + long[] dest = new long[size]; int destPos = Math.max(n, 0); - int length = n >= 0 ? size() - n : size() + n; + int length = n >= 0 ? size - n : size + n; - for (int i = 0; i < size(); i++) { + for (int i = 0; i < size; i++) { dest[i] = InstantColumnType.missingValueIndicator(); } System.arraycopy(data.toLongArray(), srcPos, dest, destPos, length); - InstantColumn copy = emptyCopy(size()); + InstantColumn copy = emptyCopy(size); copy.data = new LongArrayList(dest); copy.setName(name() + " lag(" + n + ")"); return copy; @@ -273,7 +274,7 @@ public InstantColumn appendObj(Object obj) { return append(timestamp.toInstant()); } throw new IllegalArgumentException( - "Cannot append " + obj.getClass().getName() + " to DateTimeColumn"); + "Cannot append " + obj.getClass().getName() + " to InstantColumn"); } /** {@inheritDoc} */ diff --git a/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeMapFunctions.java b/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeMapFunctions.java index 6f9460067..2d52d7e6e 100644 --- a/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeMapFunctions.java +++ b/core/src/main/java/tech/tablesaw/columns/datetimes/DateTimeMapFunctions.java @@ -50,7 +50,7 @@ import tech.tablesaw.columns.temporal.TemporalMapFunctions; import tech.tablesaw.columns.times.TimeColumnType; -public interface DateTimeMapFunctions extends TemporalMapFunctions { +public interface DateTimeMapFunctions extends TemporalMapFunctions { default IntColumn hour() { IntColumn newColumn = IntColumn.create(name() + "[" + "hour" + "]"); @@ -91,16 +91,6 @@ default IntColumn secondOfDay() { return newColumn; } - @Override - default DateTimeColumn lead(int n) { - DateTimeColumn column = lag(-n); - column.setName(name() + " lead(" + n + ")"); - return column; - } - - @Override - DateTimeColumn lag(int n); - /** Returns a TimeColumn containing the time portion of each dateTime in this DateTimeColumn */ default TimeColumn time() { TimeColumn newColumn = TimeColumn.create(this.name() + " time"); @@ -164,54 +154,6 @@ default StringColumn yearQuarter() { return newColumn; } - @Override - DateTimeColumn plus(long amountToAdd, ChronoUnit unit); - - @Override - default DateTimeColumn plusYears(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.YEARS); - } - - @Override - default DateTimeColumn plusMonths(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MONTHS); - } - - @Override - default DateTimeColumn plusWeeks(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.WEEKS); - } - - @Override - default DateTimeColumn plusDays(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.DAYS); - } - - @Override - default DateTimeColumn plusHours(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.HOURS); - } - - @Override - default DateTimeColumn plusMinutes(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MINUTES); - } - - @Override - default DateTimeColumn plusSeconds(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.SECONDS); - } - - @Override - default DateTimeColumn plusMillis(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MILLIS); - } - - @Override - default DateTimeColumn plusMicros(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MICROS); - } - /** * Returns a StringColumn with the year and month from this column concatenated into a String that * will sort lexicographically in temporal order. @@ -443,4 +385,17 @@ default IntColumn minute() { default LongColumn timeWindow(ChronoUnit unit, int n) { return timeWindow(unit, n, min()); } + + default DateTimeColumn plusYears(long amountToAdd) { + return plus(amountToAdd, ChronoUnit.YEARS); + } + + default DateTimeColumn plusMonths(long amountToAdd) { + return plus(amountToAdd, ChronoUnit.MONTHS); + } + + default DateTimeColumn plusWeeks(long amountToAdd) { + return plus(amountToAdd, ChronoUnit.WEEKS); + } + } diff --git a/core/src/main/java/tech/tablesaw/columns/instant/InstantMapFunctions.java b/core/src/main/java/tech/tablesaw/columns/instant/InstantMapFunctions.java deleted file mode 100644 index dcec16ccc..000000000 --- a/core/src/main/java/tech/tablesaw/columns/instant/InstantMapFunctions.java +++ /dev/null @@ -1,57 +0,0 @@ -package tech.tablesaw.columns.instant; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import tech.tablesaw.api.InstantColumn; -import tech.tablesaw.columns.temporal.TemporalMapFunctions; - -public interface InstantMapFunctions extends TemporalMapFunctions { - - @Override - InstantColumn plus(long amountToAdd, ChronoUnit unit); - - @Override - default InstantColumn plusYears(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.YEARS); - } - - @Override - default InstantColumn plusMonths(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MONTHS); - } - - @Override - default InstantColumn plusWeeks(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.WEEKS); - } - - @Override - default InstantColumn plusDays(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.DAYS); - } - - @Override - default InstantColumn plusHours(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.HOURS); - } - - @Override - default InstantColumn plusMinutes(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MINUTES); - } - - @Override - default InstantColumn plusSeconds(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.SECONDS); - } - - @Override - default InstantColumn plusMillis(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MILLIS); - } - - @Override - default InstantColumn plusMicros(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MICROS); - } -} diff --git a/core/src/main/java/tech/tablesaw/columns/temporal/TemporalMapFunctions.java b/core/src/main/java/tech/tablesaw/columns/temporal/TemporalMapFunctions.java index f68ac23f8..a13c065be 100644 --- a/core/src/main/java/tech/tablesaw/columns/temporal/TemporalMapFunctions.java +++ b/core/src/main/java/tech/tablesaw/columns/temporal/TemporalMapFunctions.java @@ -25,11 +25,21 @@ import tech.tablesaw.columns.Column; import tech.tablesaw.columns.booleans.BooleanColumnType; -public interface TemporalMapFunctions extends TemporalColumn { +public interface TemporalMapFunctions, T extends Temporal> extends TemporalColumn { T min(); - TemporalColumn emptyCopy(); + C emptyCopy(); + + @Override + C lag(int n); + + @Override + default C lead(int n) { + C column = lag(-n); + column.setName(name() + " lead(" + n + ")"); + return column; + } default LongColumn differenceInMilliseconds(TemporalColumn column2) { return difference(column2, ChronoUnit.MILLIS); @@ -78,41 +88,29 @@ default LongColumn difference(TemporalColumn column2, ChronoUnit unit) { return newColumn; } - Column plus(long amountToAdd, ChronoUnit unit); - - default Column plusYears(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.YEARS); - } - - default Column plusMonths(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.MONTHS); - } - - default Column plusWeeks(long amountToAdd) { - return plus(amountToAdd, ChronoUnit.WEEKS); - } + C plus(long amountToAdd, ChronoUnit unit); - default Column plusDays(long amountToAdd) { + default C plusDays(long amountToAdd) { return plus(amountToAdd, ChronoUnit.DAYS); } - default Column plusHours(long amountToAdd) { + default C plusHours(long amountToAdd) { return plus(amountToAdd, ChronoUnit.HOURS); } - default Column plusMinutes(long amountToAdd) { + default C plusMinutes(long amountToAdd) { return plus(amountToAdd, ChronoUnit.MINUTES); } - default Column plusSeconds(long amountToAdd) { + default C plusSeconds(long amountToAdd) { return plus(amountToAdd, ChronoUnit.SECONDS); } - default Column plusMillis(long amountToAdd) { + default C plusMillis(long amountToAdd) { return plus(amountToAdd, ChronoUnit.MILLIS); } - default Column plusMicros(long amountToAdd) { + default C plusMicros(long amountToAdd) { return plus(amountToAdd, ChronoUnit.MICROS); } diff --git a/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java b/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java index aa160e875..a6f8f2297 100644 --- a/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java +++ b/core/src/test/java/tech/tablesaw/api/DateTimeColumnTest.java @@ -16,31 +16,35 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.Arrays; +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import tech.tablesaw.columns.datetimes.DateTimeParser; import tech.tablesaw.columns.strings.StringColumnType; -public class DateTimeColumnTest { +class DateTimeColumnTest { private DateTimeColumn column1; @BeforeEach - public void setUp() { + void setUp() { Table table = Table.create("Test"); column1 = DateTimeColumn.create("Game date"); table.addColumns(column1); } @Test - public void testAppendCell() { + void testAppendCell() { column1.appendCell("1923-10-20T10:15:30"); column1.appendCell("1924-12-10T10:15:30"); column1.appendCell("2015-12-05T10:15:30"); @@ -52,7 +56,7 @@ public void testAppendCell() { } @Test - public void testAppendCell2() { + void testAppendCell2() { column1.appendCell("10/12/2016 12:18:03 AM"); column1.appendCell("10/2/2016 8:18:03 AM"); column1.appendCell("10/12/2016 12:18:03 AM"); @@ -60,7 +64,7 @@ public void testAppendCell2() { } @Test - public void testCustomParser() { + void testCustomParser() { // Just do enough to ensure the parser is wired up correctly DateTimeParser customParser = new DateTimeParser(ColumnType.LOCAL_DATE_TIME); customParser.setMissingValueStrings(Arrays.asList("not here")); @@ -73,7 +77,7 @@ public void testCustomParser() { } @Test - public void testConvertMillisSinceEpoch() { + void testConvertMillisSinceEpoch() { long millis = 1503952123189L; LongColumn dc = LongColumn.create("test"); dc.append(millis); @@ -91,7 +95,7 @@ public void testConvertMillisSinceEpoch() { } @Test - public void testAfter() { + void testAfter() { Table t = Table.create("test"); t.addColumns(column1); column1.appendCell("2015-12-03T10:15:30"); @@ -102,14 +106,14 @@ public void testAfter() { } @Test - public void testNull() { + void testNull() { DateTimeColumn col = DateTimeColumn.create("Game date"); col.appendCell(null); assertNull(col.get(0)); } @Test - public void testCountUnique() { + void testCountUnique() { column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); @@ -119,7 +123,7 @@ public void testCountUnique() { } @Test - public void testFormatter() { + void testFormatter() { column1.setPrintFormatter(DateTimeFormatter.ISO_LOCAL_DATE_TIME, "NaT"); column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); column1.appendMissing(); @@ -137,4 +141,90 @@ public void testAsStringColumn() { assertEquals("1923-10-20T10:15:30.000", sc.get(0)); assertEquals(StringColumnType.missingValueIndicator(), sc.get(1)); } + + @Test + void removeMissing() { + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.appendMissing(); + assertEquals(1, column1.removeMissing().size()); + assertNotNull(column1.removeMissing().get(0)); + } + + @Test + void testContains() { + column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 3, 1, 0, 0)); + assertTrue(column1.contains(LocalDateTime.of(2000, 1, 1, 0, 0))); + assertFalse(column1.contains(LocalDateTime.of(2000, 5, 1, 0, 0))); + } + + @Test + void setMissing() { + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.appendMissing(); + column1.setMissing(0); + assertEquals(2, column1.countMissing()); + } + + @Test + void testWhere() { + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.appendMissing(); + assertNull(column1.where(column1.isMissing()).get(0)); + } + + @Test + void testAsInstantColumn() { + LocalDateTime nowLdt = LocalDateTime.now().withNano(0); + DateTimeColumn dtColumn = DateTimeColumn.create("datetime", nowLdt); + InstantColumn instColumn = dtColumn.asInstantColumn(); + Instant nowInst = nowLdt.toInstant(ZoneOffset.UTC); + assertTrue(instColumn.contains(nowInst)); + } + + @Test + void testTopN() { + column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 3, 1, 0, 0)); + column1.appendMissing(); + final List top = column1.top(2); + assertEquals(2, top.size()); + assertEquals(LocalDateTime.of(2000, 3, 1, 0, 0), top.get(0)); + assertEquals(LocalDateTime.of(2000, 2, 1, 0, 0), top.get(1)); + } + + @Test + void testTopNAboveSize() { + column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 3, 1, 0, 0)); + column1.appendMissing(); + final List top = column1.top(5); + assertEquals(column1.size(), top.size()); + } + + @Test + void testBottomN() { + column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 3, 1, 0, 0)); + column1.appendMissing(); + final List bottom = column1.bottom(2); + assertEquals(2, bottom.size()); + assertNull(bottom.get(0)); + assertEquals(LocalDateTime.of(2000, 1, 1, 0, 0), bottom.get(1)); + } + + @Test + void testBottomNAboveSize() { + column1.append(LocalDateTime.of(2000, 1, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 2, 1, 0, 0)); + column1.append(LocalDateTime.of(2000, 3, 1, 0, 0)); + column1.appendMissing(); + final List bottom = column1.bottom(column1.size() + 2); + assertEquals(column1.size(), bottom.size()); + } + } diff --git a/core/src/test/java/tech/tablesaw/api/InstantColumnTest.java b/core/src/test/java/tech/tablesaw/api/InstantColumnTest.java index 4abc2cb71..cc3e7b546 100644 --- a/core/src/test/java/tech/tablesaw/api/InstantColumnTest.java +++ b/core/src/test/java/tech/tablesaw/api/InstantColumnTest.java @@ -61,7 +61,7 @@ void isNotMissing() { } @Test - public void testCountUnique() { + void testCountUnique() { InstantColumn column1 = InstantColumn.create("instants"); column1.append(baselineInst); column1.append(baselineInst); @@ -72,7 +72,7 @@ public void testCountUnique() { } @Test - public void testCustomParser() { + void testCustomParser() { class CustomParser extends AbstractColumnParser { private final List VALID_VALUES = Arrays.asList("now"); @@ -101,4 +101,106 @@ public Instant parse(String s) { column1.appendCell("now"); assertFalse(column1.isMissing(1)); } + + @Test + void testSetMissing() { + BooleanColumn missingBefore = instanceColumn.missingValues(); + assertFalse(missingBefore.get(0)); + assertFalse(missingBefore.get(1)); + assertTrue(missingBefore.get(3)); + instanceColumn.setMissing(0); + BooleanColumn missingAfter = instanceColumn.missingValues(); + assertTrue(missingAfter.get(0)); + assertFalse(missingAfter.get(1)); + assertTrue(missingBefore.get(3)); + } + + @Test + void removeMissing() { + assertEquals(3, instanceColumn.removeMissing().size()); + } + + @Test + void contains() { + assertTrue(instanceColumn.contains(baselineInst)); + assertFalse(instanceColumn.contains(baselineInst.plusSeconds(1_000))); + } + + @Test + void testSubset() { + final InstantColumn subset = instanceColumn.subset(new int[] {0, 1}); + assertEquals(2, subset.size()); + assertEquals(beforeInst, subset.get(0)); + assertEquals(baselineInst, subset.get(1)); + } + + @Test + void testWhere() { + final InstantColumn subset = instanceColumn.where(instanceColumn.isNotMissing().and(instanceColumn.isBefore(afterInst))); + assertEquals(2, subset.size()); + assertEquals(beforeInst, subset.get(0)); + assertEquals(baselineInst, subset.get(1)); + } + + @Test + void testSetSelection() { + instanceColumn.set(instanceColumn.isMissing(), afterInst); + final InstantColumn subset = instanceColumn.where(instanceColumn.isBefore(afterInst)); + assertEquals(2, subset.size()); + assertEquals(beforeInst, subset.get(0)); + assertEquals(baselineInst, subset.get(1)); + } + + @Test + void testCountMissing() { + assertEquals(1, instanceColumn.countMissing()); + } + + @Test + void testAppendColumn() { + assertEquals(8, instanceColumn.append(instanceColumn.copy()).size()); + } + + @Test + void testAppendRow() { + final InstantColumn appended = instanceColumn.append(instanceColumn.copy(), 3); + assertEquals(5, appended.size()); + assertEquals(2, appended.countMissing()); + } + + @Test + void testSetRow() { + final InstantColumn appended = instanceColumn.set(0, instanceColumn.copy(), 3); + assertEquals(4, appended.size()); + assertEquals(2, appended.countMissing()); + } + + @Test + void testTopN() { + final List top = instanceColumn.top(2); + assertEquals(2, top.size()); + assertEquals(afterInst, top.get(0)); + assertEquals(baselineInst, top.get(1)); + } + + @Test + void testTopNAboveSize() { + final List top = instanceColumn.top(10); + assertEquals(instanceColumn.size(), top.size()); + } + + @Test + void testBottomN() { + final List bottom = instanceColumn.bottom(2); + assertEquals(2, bottom.size()); + assertNull(bottom.get(0)); + assertEquals(beforeInst, bottom.get(1)); + } + + @Test + void testBottomNAboveSize() { + final List bottom = instanceColumn.bottom(instanceColumn.size() + 2); + assertEquals(instanceColumn.size(), bottom.size()); + } + } diff --git a/core/src/test/java/tech/tablesaw/columns/datetimes/DateTimeFillersTest.java b/core/src/test/java/tech/tablesaw/columns/datetimes/DateTimeFillersTest.java index b8287b507..13efaf6fc 100644 --- a/core/src/test/java/tech/tablesaw/columns/datetimes/DateTimeFillersTest.java +++ b/core/src/test/java/tech/tablesaw/columns/datetimes/DateTimeFillersTest.java @@ -8,7 +8,7 @@ import java.time.temporal.ChronoUnit; import org.junit.jupiter.api.Test; -public class DateTimeFillersTest { +class DateTimeFillersTest { private void assertContentEquals(Iterable times, LocalDateTime... expected) { int num = 0; @@ -20,61 +20,65 @@ private void assertContentEquals(Iterable times, LocalDateTime... } @Test - public void testFromToBy() { + void testFromToByDays() { assertContentEquals( create("datetimes", new LocalDateTime[5]) .fillWith( range( - LocalDateTime.of(2018, 3, 1, 12, 30), // year, month, day, hour, - // minute - LocalDateTime.of(2019, 3, 1, 12, 30), - 1, - ChronoUnit.DAYS)), - LocalDateTime.of(2018, 3, 1, 12, 30), // year, - // month, - // day, - // hour, - // minute + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30), + LocalDateTime.of(2019, 3, 1, 12, 30), + 1, ChronoUnit.DAYS)), + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30), LocalDateTime.of(2018, 3, 2, 12, 30), LocalDateTime.of(2018, 3, 3, 12, 30), LocalDateTime.of(2018, 3, 4, 12, 30), LocalDateTime.of(2018, 3, 5, 12, 30)); + } + @Test + void testFromToByHours() { + assertContentEquals( + create("datetimes", new LocalDateTime[5]) + .fillWith( + range( + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30), + LocalDateTime.of(2019, 3, 1, 12, 30), + 2, ChronoUnit.HOURS)), + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30), + LocalDateTime.of(2018, 3, 1, 14, 30), + LocalDateTime.of(2018, 3, 1, 16, 30), + LocalDateTime.of(2018, 3, 1, 18, 30), + LocalDateTime.of(2018, 3, 1, 20, 30)); + } + + @Test + void testFromToByMonths() { assertContentEquals( create("datetimes", new LocalDateTime[5]) .fillWith( range( - LocalDateTime.of(2018, 3, 1, 12, 30), // year, month, day, hour, - // minute - LocalDateTime.of(2019, 3, 1, 12, 30), - 1, - ChronoUnit.MONTHS)), - LocalDateTime.of(2018, 3, 1, 12, 30), // year, - // month, - // day, - // hour, - // minute + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30), + LocalDateTime.of(2019, 3, 1, 12, 30), + 1, ChronoUnit.MONTHS).iterator()), + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30), LocalDateTime.of(2018, 4, 1, 12, 30), LocalDateTime.of(2018, 5, 1, 12, 30), LocalDateTime.of(2018, 6, 1, 12, 30), LocalDateTime.of(2018, 7, 1, 12, 30)); + } + + @Test + void testSupplier() { + final LocalDateTime now = LocalDateTime.now().withNano(0); assertContentEquals( - create("datetimes", new LocalDateTime[5]) - .fillWith( - range( - LocalDateTime.of(2018, 3, 1, 12, 30), // year, month, day, hour, - // minute - LocalDateTime.of(2019, 3, 1, 12, 30), - 2, - ChronoUnit.HOURS)), - LocalDateTime.of(2018, 3, 1, 12, 30), // year, - // month, - // day, - // hour, - // minute - LocalDateTime.of(2018, 3, 1, 14, 30), - LocalDateTime.of(2018, 3, 1, 16, 30), - LocalDateTime.of(2018, 3, 1, 18, 30), - LocalDateTime.of(2018, 3, 1, 20, 30)); + create("instant", new LocalDateTime[5]).fillWith(() -> now), + new LocalDateTime[] {now, now, now, now, now}); + } } diff --git a/core/src/test/java/tech/tablesaw/columns/instant/InstantFillersTest.java b/core/src/test/java/tech/tablesaw/columns/instant/InstantFillersTest.java new file mode 100644 index 000000000..0164f62da --- /dev/null +++ b/core/src/test/java/tech/tablesaw/columns/instant/InstantFillersTest.java @@ -0,0 +1,106 @@ +package tech.tablesaw.columns.instant; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static tech.tablesaw.columns.temporal.fillers.TemporalRangeIterable.range; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; + +import org.junit.jupiter.api.Test; + +import tech.tablesaw.api.InstantColumn; + +class InstantFillersTest { + + private void assertContentEquals(Iterable times, Instant... expected) { + int num = 0; + for (Instant value : times) { + assertEquals(expected[num], value); + num++; + } + assertEquals(expected.length, num); + } + + @Test + void testFromToByDays() { + assertContentEquals( + InstantColumn.create("instant", new Instant[5]) + .fillWith( + range( + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2019, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + 1, ChronoUnit.DAYS)), + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 2, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 3, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 4, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 5, 12, 30).toInstant(ZoneOffset.UTC)); + } + + @Test + void testFromNbValuesByDays() { + assertContentEquals( + InstantColumn.create("instant", new Instant[5]) + .fillWith( + range( + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + 1, ChronoUnit.DAYS, 5)), + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 2, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 3, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 4, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 5, 12, 30).toInstant(ZoneOffset.UTC)); + } + + @Test + void testFromToByHours() { + assertContentEquals( + InstantColumn.create("instant", new Instant[5]) + .fillWith( + range( + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2019, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + 2, ChronoUnit.HOURS).iterator()), + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 14, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 16, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 18, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 20, 30).toInstant(ZoneOffset.UTC)); + } + + @Test + void testRepeatFromToByMinutes() { + assertContentEquals( + InstantColumn.create("instant", new Instant[5]) + .fillWith( + range( + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 12, 32).toInstant(ZoneOffset.UTC), + 1, ChronoUnit.MINUTES)), + // year, month, day, hour, minute + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 12, 31).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 12, 31).toInstant(ZoneOffset.UTC), + LocalDateTime.of(2018, 3, 1, 12, 30).toInstant(ZoneOffset.UTC)); + } + + @Test + void testSupplier() { + final Instant now = Instant.now().with(ChronoField.NANO_OF_SECOND, 0); + assertContentEquals( + InstantColumn.create("instant", new Instant[5]).fillWith(() -> now), + new Instant[] {now, now, now, now, now}); + + } +} diff --git a/core/src/test/java/tech/tablesaw/columns/instant/InstantMapFunctionsTest.java b/core/src/test/java/tech/tablesaw/columns/instant/InstantMapFunctionsTest.java new file mode 100644 index 000000000..08b9d6b1d --- /dev/null +++ b/core/src/test/java/tech/tablesaw/columns/instant/InstantMapFunctionsTest.java @@ -0,0 +1,110 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tech.tablesaw.columns.instant; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import org.junit.jupiter.api.Test; + +import tech.tablesaw.api.BooleanColumn; +import tech.tablesaw.api.InstantColumn; +import tech.tablesaw.api.LongColumn; + +/** Tests for TemporalMapFunctions with Instants */ +class InstantMapFunctionsTest { + + private InstantColumn startCol = InstantColumn.create("start"); + private InstantColumn stopCol = InstantColumn.create("stop"); + private Instant start = Instant.now(); + + @Test + void testDifferenceInMilliseconds() { + startCol.append(start); + stopCol = startCol.plusMillis(100_000L); + LongColumn result = startCol.differenceInMilliseconds(stopCol); + assertEquals(100_000L, result.getLong(0), "Wrong difference in millis"); + } + + @Test + void testDifferenceInSeconds() { + startCol.append(start); + stopCol = startCol.plusSeconds(100_000L); + LongColumn result = startCol.differenceInSeconds(stopCol); + assertEquals(100_000L, result.getLong(0), "Wrong difference in seconds"); + } + + @Test + void testDifferenceInMinutes() { + startCol.append(start); + stopCol = startCol.plusMinutes(100_000L); + LongColumn result = startCol.differenceInMinutes(stopCol); + assertEquals(100_000L, result.getLong(0), "Wrong difference in minutes"); + } + + @Test + void testDifferenceInHours() { + startCol.append(start); + stopCol = startCol.plusHours(100_000L); + LongColumn result = startCol.differenceInHours(stopCol); + assertEquals(100_000L, result.getLong(0), "Wrong difference in hours"); + } + + @Test + void testDifferenceInDays() { + startCol.append(start); + stopCol = startCol.plusDays(100_000L); + LongColumn result = startCol.differenceInDays(stopCol); + assertEquals(100_000L, result.getLong(0), "Wrong difference in days"); + } + + @Test + void testDifferenceInYears() { + startCol.append(start); + stopCol = startCol.plusDays(2L * 365); + LongColumn result = startCol.differenceInYears(stopCol); + assertEquals(2L, result.getLong(0), "Wrong difference in years"); + } + + @Test + void testLeadAndLag() { + Instant instant1 = LocalDateTime.of(2018, 4, 10, 7, 30).toInstant(ZoneOffset.UTC); + Instant instant2 = LocalDateTime.of(2018, 5, 10, 7, 30).toInstant(ZoneOffset.UTC); + Instant instant3 = LocalDateTime.of(2018, 5, 10, 7, 30).toInstant(ZoneOffset.UTC); + startCol.append(instant1); + startCol.append(instant2); + startCol.append(instant3); + InstantColumn lead = startCol.lead(1); + InstantColumn lag = startCol.lag(1); + assertEquals(startCol.get(0), lag.get(1)); + assertEquals(InstantColumnType.missingValueIndicator(), lag.getLongInternal(0)); + assertEquals(startCol.get(1), lead.get(0)); + assertEquals(InstantColumnType.missingValueIndicator(), lead.getLongInternal(2)); + } + + @Test + void testMissingValues() { + startCol.append(start); + startCol.appendMissing(); + BooleanColumn missing = startCol.missingValues(); + assertFalse(missing.get(0)); + assertTrue(missing.get(1)); + } + +}