Class MutableClock

  • All Implemented Interfaces:
    java.io.Serializable

    public final class MutableClock
    extends java.time.Clock
    implements java.io.Serializable
    A clock that does not advance on its own and that must be updated manually.

    This class is designed for testing clock-sensitive components by simulating the passage of time. This class differs from Clock.fixed(Instant, ZoneId) and Clock.offset(Clock, Duration) in that it permits arbitrary, unrestricted updates to its instant. This allows for testing patterns that are not well-supported by the fixed and offset clocks such as the following pattern:

    1. Create the clock-sensitive component to be tested
    2. Verify some behavior of the component in the initial state
    3. Advance the clock without recreating the component
    4. Verify that the component behaves as expected given the (artificial) delta in clock time since the initial state

    This class is mutable. The time-zone of the clock is fixed, but the instant may be updated at will.

    The instant may be set to any value even if that new value is less than the previous value. Caution should be exercised when moving the clock backwards, since clock-sensitive components are likely to assume that time is monotonically increasing.

    Update semantics are expressed in terms of ZonedDateTime. The steps of each update are as follows:

    1. The clock captures its own state in a ZonedDateTime via ZonedDateTime.now(Clock) (or the equivalent thereof)
    2. The update operation is applied to that ZonedDateTime, producing a new ZonedDateTime
    3. The resulting ZonedDateTime is converted to an instant via ChronoZonedDateTime.toInstant() (or the equivalent thereof)
    4. The clock's instant is set to that new instant

    Therefore, whenever there is a question about what argument types, units, fields, or values an update operation supports, or what the result will be, refer to the corresponding method of ZonedDateTime. Links are provided from the documentation of each update operation of this class to the corresponding method of ZonedDateTime.

    Implementation Requirements:

    This class is thread-safe. Updates are atomic and synchronized.

    While update semantics are expressed in terms of ZonedDateTime, that imposes no requirements on implementation details. The implementation may avoid using ZonedDateTime completely or only sometimes, for convenience, efficiency, or any other reason.

    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      void add​(long amountToAdd, java.time.temporal.TemporalUnit unit)
      Adds the specified amount to this clock.
      void add​(java.time.temporal.TemporalAmount amountToAdd)
      Adds the specified amount to this clock.
      static MutableClock epochUTC()
      Obtains a new MutableClock set to the epoch of 1970-01-01T00:00:00Z, converting to date and time using the UTC time-zone.
      boolean equals​(java.lang.Object obj)
      Returns true if obj is a MutableClock that uses the same time-zone as this clock and has shared updates with this clock.
      java.time.ZoneId getZone()  
      int hashCode()
      A hash code for this clock, which is constant for this instance.
      java.time.Instant instant()  
      static MutableClock of​(java.time.Instant instant, java.time.ZoneId zone)
      Obtains a new MutableClock set to the specified instant, converting to date and time using the specified time-zone.
      void set​(java.time.temporal.TemporalAdjuster adjuster)
      Adjusts this clock.
      void set​(java.time.temporal.TemporalField field, long newValue)
      Alters the specified field of this clock.
      void setInstant​(java.time.Instant instant)
      Overrides the instant of this clock with the specified value.
      java.lang.String toString()  
      MutableClock withZone​(java.time.ZoneId zone)
      Returns a MutableClock that uses the specified time-zone and that has shared updates with this clock.
      • Methods inherited from class java.time.Clock

        fixed, millis, offset, system, systemDefaultZone, systemUTC, tick, tickMillis, tickMinutes, tickSeconds
      • Methods inherited from class java.lang.Object

        clone, finalize, getClass, notify, notifyAll, wait, wait, wait
    • Method Detail

      • epochUTC

        public static MutableClock epochUTC()
        Obtains a new MutableClock set to the epoch of 1970-01-01T00:00:00Z, converting to date and time using the UTC time-zone.

        Use this method when a MutableClock is needed and neither its initial value nor its time-zone are important. This is often true when testing behavior that depends on elapsed relative time rather than absolute time.

        Returns:
        a new MutableClock, not null
      • of

        public static MutableClock of​(java.time.Instant instant,
                                      java.time.ZoneId zone)
        Obtains a new MutableClock set to the specified instant, converting to date and time using the specified time-zone.
        Parameters:
        instant - the initial value for the clock, not null
        zone - the time-zone to use, not null
        Returns:
        a new MutableClock, not null
      • setInstant

        public void setInstant​(java.time.Instant instant)
        Overrides the instant of this clock with the specified value.
        Parameters:
        instant - the new instant for this clock, not null
      • add

        public void add​(java.time.temporal.TemporalAmount amountToAdd)
        Adds the specified amount to this clock.

        Atomically updates this clock to the value of the following expression:

           ZonedDateTime.now(thisClock)
                        .plus(amountToAdd)
                        .toInstant()
         
        Parameters:
        amountToAdd - the amount to add, not null
        Throws:
        java.time.DateTimeException - if the addition cannot be made
        java.lang.ArithmeticException - if numeric overflow occurs
        See Also:
        ZonedDateTime.plus(TemporalAmount)
      • add

        public void add​(long amountToAdd,
                        java.time.temporal.TemporalUnit unit)
        Adds the specified amount to this clock.

        Atomically updates this clock to the value of the following expression:

           ZonedDateTime.now(thisClock)
                        .plus(amountToAdd, unit)
                        .toInstant()
         
        Parameters:
        amountToAdd - the amount of the specified unit to add, may be negative
        unit - the unit of the amount to add, not null
        Throws:
        java.time.DateTimeException - if the unit cannot be added
        java.time.temporal.UnsupportedTemporalTypeException - if the unit is not supported
        java.lang.ArithmeticException - if numeric overflow occurs
        See Also:
        ZonedDateTime.plus(long, TemporalUnit)
      • set

        public void set​(java.time.temporal.TemporalAdjuster adjuster)
        Adjusts this clock.

        Atomically updates this clock to the value of the following expression:

           ZonedDateTime.now(thisClock)
                        .with(adjuster)
                        .toInstant()
         
        Parameters:
        adjuster - the adjuster to use, not null
        Throws:
        java.time.DateTimeException - if the adjustment cannot be made
        java.lang.ArithmeticException - if numeric overflow occurs
        See Also:
        ZonedDateTime.with(TemporalAdjuster)
      • set

        public void set​(java.time.temporal.TemporalField field,
                        long newValue)
        Alters the specified field of this clock.

        Atomically updates this clock to the value of the following expression:

           ZonedDateTime.now(thisClock)
                        .with(field, newValue)
                        .toInstant()
         
        Parameters:
        field - the field to set, not null
        newValue - the new value of the field
        Throws:
        java.time.DateTimeException - if the field cannot be set
        java.time.temporal.UnsupportedTemporalTypeException - if the field is not supported
        java.lang.ArithmeticException - if numeric overflow occurs
        See Also:
        ZonedDateTime.with(TemporalField, long)
      • getZone

        public java.time.ZoneId getZone()
        Specified by:
        getZone in class java.time.Clock
      • withZone

        public MutableClock withZone​(java.time.ZoneId zone)
        Returns a MutableClock that uses the specified time-zone and that has shared updates with this clock.

        Two clocks with shared updates always have the same instant, and all updates applied to either clock affect both clocks.

        Specified by:
        withZone in class java.time.Clock
        Parameters:
        zone - the time-zone to use for the returned clock, not null
        Returns:
        a view of this clock in the specified time-zone, not null
      • instant

        public java.time.Instant instant()
        Specified by:
        instant in class java.time.Clock
      • equals

        public boolean equals​(java.lang.Object obj)
        Returns true if obj is a MutableClock that uses the same time-zone as this clock and has shared updates with this clock.

        Two clocks with shared updates always have the same instant, and all updates applied to either clock affect both clocks.

        A deserialized MutableClock is not equal to the original clock that was serialized, since the two clocks do not have shared updates.

        Overrides:
        equals in class java.time.Clock
        Parameters:
        obj - the object to check, null returns false
        Returns:
        true if this is equal to the other clock
      • hashCode

        public int hashCode()
        A hash code for this clock, which is constant for this instance.
        Overrides:
        hashCode in class java.time.Clock
        Returns:
        a constant hash code for this instance
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object