Skip to content

Getting started

Installation

Releases are published to maven central.

MavenCentral

It can be included in your project by including the following in your project's build configuration.

dependencies {
    testImplementation 'com.hypercubetools:timeslip:0.1.0'
}
<dependency>
  <groupId>com.hypercubetools</groupId>
  <artifactId>timeslip</artifactId>
  <version>0.1.0</version>
  <type>pom</type>
</dependency>

Usage Examples

Let's look at a class which uses a Clock as part of the implementation.

import java.time.Clock
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoField

class Greeter(private val _clock: Clock = Clock.systemDefaultZone()) {
    fun sayHello(name :String) = if (beforeNoon())  "Morning $name" else "Afternoon $name"

    fun displayTime() = 
        println(DateTimeFormatter.ISO_TIME.withZone(_clock.zone).format(_clock.instant()))

    private fun beforeNoon() = 
        LocalDateTime.ofInstant(_clock.instant(), _clock.zone).get(ChronoField.AMPM_OF_DAY) == 0
}
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.temporal.ChronoField;

class Greeter {
    private final Clock _clock;

    public Greeter() {
        this(Clock.systemDefaultZone());
    }

    public Greeter(Clock clock) {
        _clock = clock;
    }

    public String sayHello(String name) {
        if (beforeNoon()) {
            return "Morning " + name;
        }
        return "Afternoon " + name;
    }

    public void displayTime() {
        System.out.println(DateTimeFormatter.ISO_TIME.withZone(_clock.zone).format(_clock.instant()));
    }

    private boolean beforeNoon() {
        return LocalDateTime.ofInstant(_clock.instant(), _clock.getZone()).get(ChronoField.AMPM_OF_DAY) == 0;
    } 
}

Normally a Greeter would be created with the no argument constructor. Since the Clock returned by Clock.systemDefaultZone() is non-deterministic, it is not suitable for automated testing. TimeSlip produces a Clock that can be configured to operated in a known way.

import java.time.Instant
import com.hypercubetools.timeslip.TimeSlip

fun main() {
    val greeter = Greeter(TimeSlip.at(Instant.parse("2007-12-03T10:15:30.00Z")))

    println(greeter.sayHello("Alice"))
    println(greeter.sayHello("Bob"))
}
import java.time.Instant;
import com.hypercubetools.timeslip.TimeSlip;

class Example {
    public static void main(String[] args) {
        Greeter greeter = Greeter(TimeSlip.at(Instant.parse("2007-12-03T10:15:30.00Z")));

        System.out.println(greeter.sayHello("Alice"));
        System.out.println(greeter.sayHello("Bob"));
    }
}

This code will always produce the following output.

Mourning Alice
Mourning Bob

However, since applications expect time to progress forward, it is useful to produce a Clock that moves in a deterministic way.

import java.time.Duration
import java.time.Instant
import com.hypercubetools.timeslip.TimeSlip

fun main() {
    val greeter = Greeter(TimeSlip.startAt(Instant.parse("2007-12-03T10:15:30.00Z"), tickAmount = Duration.ofMinutes(2)))

    greeter.displayTime()
    greeter.displayTime()
    greeter.displayTime()
}
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneOffset;
import com.hypercubetools.timeslip.TimeSlip;

class Example {
    public static void main(String[] args) {
        Greeter greeter = new Greeter(TimeSlip.startAt(Instant.parse("2007-12-03T10:15:30.00Z"), ZoneOffset.UTC, Duration.ofMinutes(2)));

        greeter.displayTime();
        greeter.displayTime();
        greeter.displayTime();
    }
}

This code will always produce the following output.

10:15:30Z
10:17:30Z
10:19:30Z

Read the Usage Guide to see more detailed descriptions of the ways TimeSlip can be configured.