Skip to content

Commit

Permalink
Fixes #20: Added a Kata for Clock API
Browse files Browse the repository at this point in the history
  • Loading branch information
c-guntur committed Oct 19, 2020
1 parent 88c3875 commit b7db318
Show file tree
Hide file tree
Showing 11 changed files with 450 additions and 40 deletions.
24 changes: 14 additions & 10 deletions java-datetime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,23 @@ The JUnit tests listed below are setup to utilize the Java Time API features.

The tests in this class show interoperability between `java.util.Date` and the newer `java.time.Instant`.

1. ##### [TestKata2LocalAndZonedDateTimes.java](src/test/java/none/cvg/datetime/TestKata2LocalAndZonedDateTimes.java)
1. ##### [TestKata2Clocks.java](src/test/java/none/cvg/datetime/TestKata2Clocks.java)

The tests in this class show the usage of `java.time.LocalDate`, `java.time.LocalTime`, `java.time.LocalDateTime` and `java.time.ZonedDateTime`.
In addition, this class introduces a `java.time.Clock` that is extremely handy in writing tests.
The tests in this class show the usage of `java.time.Clock`.

1. ##### [TestKata3PeriodsAndDurations.java](src/test/java/none/cvg/datetime/TestKata3PeriodsAndDurations.java)
1. ##### [TestKata3LocalAndZonedDateTimes.java](src/test/java/none/cvg/datetime/TestKata3LocalAndZonedDateTimes.java)

The tests in this class show the usage of `java.time.LocalDate`, `java.time.LocalTime`, `java.time.LocalDateTime` and `java.time.ZonedDateTime`.

1. ##### [TestKata4PeriodsAndDurations.java](src/test/java/none/cvg/datetime/TestKata4PeriodsAndDurations.java)

The tests in this class show the usage of DateTime ranges: Period, Duration tests.

1. ##### [TestKata4DateTimePartials.java](src/test/java/none/cvg/datetime/TestKata4DateTimePartials.java)
1. ##### [TestKata5DateTimePartials.java](src/test/java/none/cvg/datetime/TestKata5DateTimePartials.java)

The tests in this class show the usage of DateTime partials: Month, MonthDay, Year, YearMonth and DayOfWeek tests.

1. ##### [TestKata5StreamsInDateTime.java](src/test/java/none/cvg/datetime/TestKata5StreamsInDateTime.java)
1. ##### [TestKata6StreamsInDateTime.java](src/test/java/none/cvg/datetime/TestKata6StreamsInDateTime.java)

The tests in this class show the usage of DateTime in Java `stream()` lazy iterations.

Expand All @@ -121,10 +124,11 @@ Solutions for each test:
Kata Test | Solution
------------ | -------------
[TestKata1InstantAndDateInterop.java](src/test/java/none/cvg/datetime/TestKata1InstantAndDateInterop.java) | [TestSolution1InstantAndDateInterop.java](src/solutions/java/none/cvg/datetime/TestSolution1InstantAndDateInterop.java)
[TestKata2LocalAndZonedDateTimes.java](src/test/java/none/cvg/datetime/TestKata2LocalAndZonedDateTimes.java) | [TestSolution2LocalAndZonedDateTimes.java](src/solutions/java/none/cvg/datetime/TestSolution2LocalAndZonedDateTimes.java)
[TestKata3PeriodsAndDurations.java](src/test/java/none/cvg/datetime/TestKata3PeriodsAndDurations.java) | [TestSolution3PeriodsAndDurations.java](src/solutions/java/none/cvg/datetime/TestSolution3PeriodsAndDurations.java)
[TestKata4DateTimePartials.java](src/test/java/none/cvg/datetime/TestKata4DateTimePartials.java) | [TestSolution4DateTimePartials.java](src/solutions/java/none/cvg/datetime/TestSolution4DateTimePartials.java)
[TestKata5StreamsInDateTime.java](src/test/java/none/cvg/datetime/TestKata5StreamsInDateTime.java) | [TestSolution5StreamsInDateTime.java](src/solutions/java/none/cvg/datetime/TestSolution5StreamsInDateTime.java)
[TestKata2Clocks.java](src/test/java/none/cvg/datetime/TestKata2Clocks.java) | [TestSolution2Clocks.java](src/solutions/java/none/cvg/datetime/TestSolution2Clocks.java)
[TestKata3LocalAndZonedDateTimes.java](src/test/java/none/cvg/datetime/TestKata3LocalAndZonedDateTimes.java) | [TestSolution3LocalAndZonedDateTimes.java](src/solutions/java/none/cvg/datetime/TestSolution3LocalAndZonedDateTimes.java)
[TestKata4PeriodsAndDurations.java](src/test/java/none/cvg/datetime/TestKata4PeriodsAndDurations.java) | [TestSolution4PeriodsAndDurations.java](src/solutions/java/none/cvg/datetime/TestSolution4PeriodsAndDurations.java)
[TestKata5DateTimePartials.java](src/test/java/none/cvg/datetime/TestKata5DateTimePartials.java) | [TestSolution5DateTimePartials.java](src/solutions/java/none/cvg/datetime/TestSolution5DateTimePartials.java)
[TestKata6StreamsInDateTime.java](src/test/java/none/cvg/datetime/TestKata6StreamsInDateTime.java) | [TestSolution6StreamsInDateTime.java](src/solutions/java/none/cvg/datetime/TestSolution6StreamsInDateTime.java)


## <a name="TakeAway"></a>Take Away
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package none.cvg.datetime;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.ChronoField;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* The tests in this class aim to show `java.time.Clock` usage.
*
* @see Clock
*/
@DisplayNameGeneration(DateTimeKataDisplayNames.class)
@DisplayName("Clock API")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestSolution2Clocks {

@Test
@Tag("PASSING")
@Order(1)
public void useSystemClock() {

// Get current ZoneOffset
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZoneOffset offset = offsetDateTime.getOffset();

// DONE: Create a system clock
// Given a date of 2005-05-05 and a time on 05:05:05 AM in GMT -5,
// fix it to display in GMT +1. Show the same Instant in a different zone.
// Check: java.time.Clock.withZoneSameInstant(java.time.ZoneId)
//-----------------------------------------
Clock systemClock = Clock.systemDefaultZone();

LocalDateTime localDateTimeWithoutClock = LocalDateTime.now();

// DONE: Use a system clock instead of the LocalDateTime.of(...)
// Check: LocalDateTime.now(java.time.Clock)
//-----------------------------------------
LocalDateTime localDateTimeWithClock = LocalDateTime.now(systemClock);

long secondsWithoutClock = localDateTimeWithoutClock.toEpochSecond(offset);
long secondsWithClock = localDateTimeWithClock.toEpochSecond(offset);

// Since the times are created sequentially, it may be possible that a second may
// have elapsed/ticked since the first date was generated. Hence we check for the
// difference being a second or less.
assertTrue(Math.abs(secondsWithClock - secondsWithoutClock) <= 1);
}

@Test
@Tag("PASSING")
@Order(2)
public void useFixedClock() {

// Get current ZoneOffset
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZoneOffset offset = offsetDateTime.getOffset();

Instant utcHALBirthday = Instant.parse("1999-01-12T00:00:00.001-08:00");

// DONE: Replace SystemClock with a FixedClock to always generate the same date and time
// Check: Clock.fixed(java.time.Instant, java.time.ZoneId)
// Check: ZoneId.of(String) which can accept "UTC" as a value
Clock utcClockForHAL = Clock.fixed(utcHALBirthday, ZoneId.of("UTC"));

// DONE: Replace the SystemClock with the FixedClock instance
LocalDate birthDateForHAL = LocalDate.now(utcClockForHAL);

// DONE: Replace the SystemClock with the FixedClock instance
LocalDateTime birthDateAndTimeForHAL = LocalDateTime.now(utcClockForHAL);

assertEquals(1999,
birthDateForHAL.getYear(),
"HAL birth year should be 1999");

assertEquals(8,
birthDateAndTimeForHAL.getLong(ChronoField.HOUR_OF_DAY),
"HAL was born 8 AM UTC");

assertEquals(1,
birthDateAndTimeForHAL.getLong(ChronoField.MILLI_OF_SECOND),
"HAL was born 1 millisecond past midnight, Pacific Time");
}

@Test
@Tag("PASSING")
@Order(3)
public void useOffsetClock() {

// Get current ZoneOffset
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZoneOffset offset = offsetDateTime.getOffset();

// Create a Duration of 1 hour. More on this in another Kata example.
Duration oneHour = Duration.ofHours(1L);

Instant utcHALBirthday = Instant.parse("1999-01-12T00:00:00.001-08:00");
Clock utcClock = Clock.fixed(utcHALBirthday, ZoneId.of("UTC"));

// DONE: Replace SystemClock with an OffsetClock, offset by a Duration of 1 HOUR.
// Check: Clock.offset(java.time.Clock, java.time.Duration)
Clock plusOneHourClock = Clock.offset(utcClock, oneHour);

// DONE: Use the utcClock instance
LocalTime utcTime = LocalTime.now(utcClock);

// DONE: Use the plusOneDayClock instance
LocalTime plusOneHourTime = LocalTime.now(plusOneHourClock);

assertEquals(1,
plusOneHourTime.getHour() - utcTime.getHour(),
"There should be an hour difference in offset");
}

@Test
@Tag("PASSING")
@Order(4)
public void useTickClock() {

// *****************************************************
// Think of a tick as being similar to how hands on an
// analog watch move. If a watch does not have a seconds
// hand, the only time there is a movement is when 60
// seconds complete (which may then move the minute and
// possibly the hour hand).
// *****************************************************

// Get current ZoneOffset
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZoneOffset offset = offsetDateTime.getOffset();

// Create a Duration of 30 seconds. More on this in another Kata example.
Duration thirtySeconds = Duration.ofSeconds(30L);

// No tick
Instant utcInstant1 = Instant.parse("1999-01-12T00:00:00.000-08:00");
Clock utcClock1 = Clock.fixed(utcInstant1, ZoneId.of("UTC"));
// DONE: Replace the FixedClock with a TickClock.
// Check: Clock.tick(java.time.Clock, java.time.Duration)
Clock plusThirtySecondTickClock1 = Clock.tick(utcClock1, thirtySeconds);


// No tick
Instant utcInstant2 = Instant.parse("1999-01-12T00:00:10.000-08:00");
Clock utcClock2 = Clock.fixed(utcInstant2, ZoneId.of("UTC"));
// DONE: Replace the FixedClock with a TickClock.
// Check: Clock.tick(java.time.Clock, java.time.Duration)
Clock plusThirtySecondTickClock2 = Clock.tick(utcClock2, thirtySeconds);


// No tick
Instant utcInstant3 = Instant.parse("1999-01-12T00:00:20.000-08:00");
Clock utcClock3 = Clock.fixed(utcInstant3, ZoneId.of("UTC"));
// DONE: Replace the FixedClock with a TickClock.
// Check: Clock.tick(java.time.Clock, java.time.Duration)
Clock plusThirtySecondTickClock3 = Clock.tick(utcClock3, thirtySeconds);


// Should have a tick
Instant utcInstant4 = Instant.parse("1999-01-12T00:00:30.000-08:00");
Clock utcClock4 = Clock.fixed(utcInstant4, ZoneId.of("UTC"));
// DONE: Replace the FixedClock with a TickClock.
// Check: Clock.tick(java.time.Clock, java.time.Duration)
Clock plusThirtySecondTickClock4 = Clock.tick(utcClock4, thirtySeconds);


// No tick
assertTrue(utcClock1.instant().equals(plusThirtySecondTickClock1.instant()),
"The instant is less than the tick time of 30 seconds");

// No tick
assertTrue(utcClock1.instant().equals(plusThirtySecondTickClock2.instant()),
"The instant is less than the tick time of 30 seconds");

// No tick
assertTrue(utcClock1.instant().equals(plusThirtySecondTickClock3.instant()),
"The instant is less than the tick time of 30 seconds");

// Should have a tick
assertFalse(utcClock1.instant().equals(plusThirtySecondTickClock4.instant()),
"The instant is not less than the tick time of 30 seconds");

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
@DisplayNameGeneration(DateTimeKataDisplayNames.class)
@DisplayName("Local and Zoned Date Time manipulations")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestSolution2LocalAndZonedDateTimes {
public class TestSolution3LocalAndZonedDateTimes {

// Using a clock as a standard reference for testing any time
// (even after any possible timezone changes)
Expand All @@ -48,15 +48,15 @@ public class TestSolution2LocalAndZonedDateTimes {
@BeforeEach
public void setup() {

Instant instant = Instant.parse("1997-08-29T07:14:30Z");
Instant instant = Instant.parse("1997-08-29T06:14:30Z");
// *****************************************************
// We make an assumption for GMT -5 as the standard
// We make an assumption for GMT -4 as the standard
// time for users of this test. This is because it is
// widely believed that the Judgement Day was triggered
// in New York City & Washington DC, both of which share
// the GMT -5 timezone.
// the GMT -4 (Eastern Daylight Time) timezone in August.
// *****************************************************
terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-5"));
terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-4"));
}

@Test
Expand Down Expand Up @@ -276,10 +276,10 @@ public void verifyZonedDateTimeUsingClock() {
LocalDateTime.now(terminatorOriginalJudgementDay);

Instant tojdInstant = theOriginalJudgementDayDateTime
.toInstant(ZoneOffset.of("+0000"));
.toInstant(ZoneOffset.of("-04:00"));

// DONE: Replace ZonedDateTime.now() to get date time in GMT +1 offset.
// Given a timestamp of 1997-08-29T07:14:30Z,
// Given a timestamp of 1997-08-29T06:14:30Z,
// fix it to display in GMT +1. Show the same Instant in a different zone.
// Check: java.time.ZonedDateTime.ofInstant(java.time.Instant, java.time.ZoneId)
ZonedDateTime gmtPlusOneHourTimeForTOJD =
Expand All @@ -289,7 +289,7 @@ public void verifyZonedDateTimeUsingClock() {
gmtPlusOneHourTimeForTOJD.getMonthValue(),
"The expected and actual month values should match");

assertEquals(3,
assertEquals(7,
gmtPlusOneHourTimeForTOJD.getHour(),
"The expected and actual hour values should match");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@
@DisplayNameGeneration(DateTimeKataDisplayNames.class)
@DisplayName("Periods (days, months years) and Durations (hours minutes, seconds")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestSolution3PeriodsAndDurations {
public class TestSolution4PeriodsAndDurations {

private Clock terminatorOriginalJudgementDay = null;

@BeforeEach
public void setup() {

Instant instant = Instant.parse("1997-08-29T07:14:30Z");
Instant instant = Instant.parse("1997-08-29T06:14:30Z");
// We make an assumption for GMT - 5 as the standard time for users of this test.
terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-5"));
terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-4"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@
@DisplayNameGeneration(DateTimeKataDisplayNames.class)
@DisplayName("Date and Time partials such as credit card expiration")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestSolution4DateTimePartials {
public class TestSolution5DateTimePartials {

private Clock terminatorOriginalJudgementDay = null;

@BeforeEach
public void setup() {

Instant instant = Instant.parse("1997-08-29T07:14:30Z");
Instant instant = Instant.parse("1997-08-29T06:14:30Z");
// We make an assumption for GMT - 5 as the standard time for users of this test.
terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-5"));
terminatorOriginalJudgementDay = Clock.fixed(instant, ZoneId.of("GMT-4"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
@DisplayNameGeneration(DateTimeKataDisplayNames.class)
@DisplayName("Temporal Adjusters and Dates in Streams")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestSolution5StreamsInDateTime {
public class TestSolution6StreamsInDateTime {

@Test
@Tag("PASSING")
Expand Down
Loading

0 comments on commit b7db318

Please sign in to comment.