├── .gitignore ├── README.md ├── pom.xml └── src ├── test └── java │ └── com │ └── statemachinesystems │ └── mockclock │ └── MockClockTest.java └── main └── java └── com └── statemachinesystems └── mockclock └── MockClock.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.next 5 | dependency-reduced-pom.xml 6 | release.properties 7 | .idea/ 8 | *.iml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Java 8's `Clock` class is a big step in the right direction for testability, but it's still a pain. You can 2 | test using `Clock.fixed()` but that's immutable so you can't test how your code responds to the passage of time. 3 | You can use a mocking library to stub the `instant()` and `getZone()` methods, but that's still awkward and indirect. 4 | 5 | This library provides a mutable `MockClock` class that can be constructed as of a given date and time, then adjusted as 6 | needed. Here's an example of how to use it: 7 | 8 | 9 | import com.statemachinesystems.mockclock.MockClock; 10 | import java.time.ZoneId; 11 | 12 | MockClock clock = MockClock.at(2015, 12, 10, 11, 16, ZoneId.of("UTC")); 13 | ClassUnderTest testSubject = new ClassUnderTest(clock); 14 | 15 | assertThat(testSubject.someMethod(), is(expectedValueAtStartTime)); 16 | 17 | clock.advanceBySeconds(30); 18 | 19 | assertThat(testSubject.someMethod(), is(expectedValueAfter30Seconds)); 20 | 21 | This library is in the Maven Central repo, so just add the following chunk to your pom.xml (or the equivalent for Gradle/SBT/whatever): 22 | 23 | 24 | com.statemachinesystems 25 | mock-clock 26 | 1.0 27 | 28 | 29 | 30 | © 2015 State Machine Systems Ltd. [Apache Licence, Version 2.0]( http://www.apache.org/licenses/LICENSE-2.0) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.statemachinesystems 6 | mock-clock 7 | 1.1-SNAPSHOT 8 | jar 9 | 10 | mock-clock 11 | A mock Clock implementation for Java. 12 | https://github.com/state-machine-systems/mock-clock 13 | 14 | 15 | 16 | Apache License, Version 2.0 17 | http://www.apache.org/licenses/LICENSE-2.0.txt 18 | repo 19 | 20 | 21 | 22 | 23 | scm:git:git@github.com:state-machine-systems/mock-clock.git 24 | scm:git:git@github.com:state-machine-systems/mock-clock.git 25 | git@github.com:state-machine-systems/mock-clock.git 26 | HEAD 27 | 28 | 29 | 30 | 31 | johnwright 32 | John Wright 33 | john@statemachinesystems.co.uk 34 | State Machine Systems 35 | http://www.statemachinesystems.co.uk 36 | 37 | 38 | 39 | 40 | 0.7.1.201405082137 41 | 1.8 42 | 1.8 43 | 4.12 44 | 3.1 45 | 2.8.2 46 | 1.5 47 | 2.10.1 48 | 2.5.1 49 | 2.4 50 | 2.17 51 | UTF-8 52 | 53 | 54 | 55 | 56 | junit 57 | junit 58 | ${junit.version} 59 | test 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-compiler-plugin 68 | ${maven.compiler.plugin.version} 69 | 70 | ${java.source.version} 71 | ${java.target.version} 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-surefire-plugin 77 | ${maven.surefire.plugin.version} 78 | 79 | 80 | default-test 81 | test 82 | 83 | test 84 | 85 | 86 | ${jacocoAgentConfigArgs} 87 | 88 | **/integration/*.* 89 | 90 | 91 | 92 | 93 | 94 | 95 | org.jacoco 96 | jacoco-maven-plugin 97 | ${jacoco.version} 98 | 99 | 100 | jacoco-init 101 | process-test-classes 102 | 103 | prepare-agent 104 | 105 | 106 | jacocoAgentConfigArgs 107 | 108 | 109 | 110 | jacoco-report 111 | verify 112 | 113 | report 114 | 115 | 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-release-plugin 121 | ${maven.release.plugin.version} 122 | 123 | 124 | org.apache.maven.plugins 125 | maven-source-plugin 126 | ${maven.source.plugin.version} 127 | 128 | 129 | attach-sources 130 | 131 | jar 132 | 133 | 134 | 135 | 136 | 137 | org.apache.maven.plugins 138 | maven-javadoc-plugin 139 | ${maven.javadoc.plugin.version} 140 | 141 | 142 | attach-javadocs 143 | 144 | jar 145 | 146 | 147 | 148 | 149 | 150 | org.apache.maven.plugins 151 | maven-deploy-plugin 152 | ${maven.deploy.plugin.version} 153 | 154 | 155 | 156 | 157 | 158 | 159 | release-sign-artifacts 160 | 161 | 162 | performRelease 163 | true 164 | 165 | 166 | 167 | 168 | 169 | org.apache.maven.plugins 170 | maven-gpg-plugin 171 | ${maven.gpg.plugin.version} 172 | 173 | true 174 | 175 | 176 | 177 | sign-artifacts 178 | verify 179 | 180 | sign 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | sonatype-nexus-snapshots 193 | Sonatype Nexus snapshot repository 194 | https://oss.sonatype.org/content/repositories/snapshots 195 | 196 | 197 | sonatype-nexus-staging 198 | Sonatype Nexus release repository 199 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 200 | 201 | 202 | -------------------------------------------------------------------------------- /src/test/java/com/statemachinesystems/mockclock/MockClockTest.java: -------------------------------------------------------------------------------- 1 | package com.statemachinesystems.mockclock; 2 | 3 | import java.time.Clock; 4 | import java.time.Duration; 5 | import java.time.Instant; 6 | import java.time.LocalDate; 7 | import java.time.LocalDateTime; 8 | import java.time.LocalTime; 9 | import java.time.Month; 10 | import java.time.ZoneId; 11 | import java.time.ZonedDateTime; 12 | import org.junit.Test; 13 | 14 | import static java.time.Month.*; 15 | import static org.hamcrest.CoreMatchers.is; 16 | import static org.junit.Assert.assertThat; 17 | 18 | public class MockClockTest { 19 | 20 | private static final ZoneId UTC = ZoneId.of("UTC"); 21 | 22 | private static final int YEAR = 2015; 23 | private static final Month MONTH = DECEMBER; 24 | private static final int DAY_OF_MONTH = 9; 25 | private static final int HOUR = 12; 26 | private static final int MINUTE = 25; 27 | private static final int SECOND = 38; 28 | private static final int NANO_OF_SECOND = 111; 29 | private static final LocalDate LOCAL_DATE = LocalDate.of(YEAR, MONTH, DAY_OF_MONTH); 30 | private static final LocalTime LOCAL_TIME = LocalTime.of(HOUR, MINUTE, SECOND, NANO_OF_SECOND); 31 | private static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.of(LOCAL_DATE, LOCAL_TIME); 32 | private static final Instant DATE_TIME_INSTANT = LOCAL_DATE_TIME.atZone(UTC).toInstant(); 33 | private static final Instant DATE_ONLY_INSTANT = LOCAL_DATE.atStartOfDay(UTC).toInstant(); 34 | 35 | @Test 36 | public void constructUsingSystemClock() { 37 | Clock systemClock = Clock.system(UTC); 38 | Instant now = systemClock.instant(); 39 | 40 | MockClock mockClock = MockClock.now(UTC).setNano(0); 41 | 42 | Instant roundedInstant = ZonedDateTime.ofInstant(now, UTC).withNano(0).toInstant(); 43 | assertClockInstant(mockClock, roundedInstant); 44 | } 45 | 46 | @Test 47 | public void constructFromClock() { 48 | Clock fixedClock = Clock.fixed(DATE_TIME_INSTANT, UTC); 49 | MockClock mockClock = MockClock.at(fixedClock); 50 | 51 | assertClockInstant(mockClock, DATE_TIME_INSTANT); 52 | } 53 | 54 | @Test 55 | public void constructFromInstant() { 56 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 57 | 58 | assertClockInstant(mockClock, DATE_TIME_INSTANT); 59 | } 60 | 61 | @Test 62 | public void constructFromZonedDateTime() { 63 | ZonedDateTime zonedDateTime = LOCAL_DATE_TIME.atZone(UTC); 64 | MockClock mockClock = MockClock.at(zonedDateTime); 65 | 66 | assertClockInstant(mockClock, DATE_TIME_INSTANT); 67 | } 68 | 69 | @Test 70 | public void constructFromLocalDateTime() { 71 | MockClock mockClock = MockClock.at(LOCAL_DATE_TIME, UTC); 72 | 73 | assertClockInstant(mockClock, DATE_TIME_INSTANT); 74 | } 75 | 76 | @Test 77 | public void constructFromLocalDate() { 78 | MockClock mockClock = MockClock.at(LOCAL_DATE, UTC); 79 | 80 | assertClockInstant(mockClock, DATE_ONLY_INSTANT); 81 | } 82 | 83 | @Test 84 | public void constructFromLocalDateAndLocalTime() { 85 | MockClock mockClock = MockClock.at(LOCAL_DATE, LOCAL_TIME, UTC); 86 | 87 | assertClockInstant(mockClock, DATE_TIME_INSTANT); 88 | } 89 | 90 | @Test 91 | public void constructFromFullDateAndTimeWithNanoResolution() { 92 | MockClock mockClock = MockClock.at(YEAR, DECEMBER, DAY_OF_MONTH, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC); 93 | 94 | assertClockInstant(mockClock, DATE_TIME_INSTANT); 95 | } 96 | 97 | @Test 98 | public void constructFromFullDateAndTimeWithSecondResolution() { 99 | MockClock mockClock = MockClock.at(YEAR, DECEMBER, DAY_OF_MONTH, HOUR, MINUTE, SECOND, UTC); 100 | 101 | assertClockInstant(mockClock, DATE_TIME_INSTANT.minusNanos(NANO_OF_SECOND)); 102 | } 103 | 104 | @Test 105 | public void constructFromFullDateAndTimeWithMinuteResolution() { 106 | MockClock mockClock = MockClock.at(YEAR, DECEMBER, DAY_OF_MONTH, HOUR, MINUTE, UTC); 107 | 108 | assertClockInstant(mockClock, DATE_TIME_INSTANT.minusNanos(NANO_OF_SECOND).minusSeconds(SECOND)); 109 | } 110 | 111 | @Test 112 | public void constructFromFullDate() { 113 | MockClock mockClock = MockClock.at(YEAR, DECEMBER, DAY_OF_MONTH, UTC); 114 | 115 | assertClockInstant(mockClock, DATE_ONLY_INSTANT); 116 | } 117 | 118 | @Test 119 | public void constructFromFullDateAndTimeWithIntegerMonthAndNanoResolution() { 120 | MockClock mockClock = MockClock.at(YEAR, 12, DAY_OF_MONTH, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC); 121 | 122 | assertClockInstant(mockClock, DATE_TIME_INSTANT); 123 | } 124 | 125 | @Test 126 | public void constructFromFullDateAndTimeWithIntegerMonthAndSecondResolution() { 127 | MockClock mockClock = MockClock.at(YEAR, 12, DAY_OF_MONTH, HOUR, MINUTE, SECOND, UTC); 128 | 129 | assertClockInstant(mockClock, DATE_TIME_INSTANT.minusNanos(NANO_OF_SECOND)); 130 | } 131 | 132 | @Test 133 | public void constructFromFullDateAndTimeWithIntegerMonthAndMinuteResolution() { 134 | MockClock mockClock = MockClock.at(YEAR, 12, DAY_OF_MONTH, HOUR, MINUTE, UTC); 135 | 136 | assertClockInstant(mockClock, DATE_TIME_INSTANT.minusNanos(NANO_OF_SECOND).minusSeconds(SECOND)); 137 | } 138 | 139 | @Test 140 | public void constructFromFullDateWithIntegerMonth() { 141 | MockClock mockClock = MockClock.at(YEAR, 12, DAY_OF_MONTH, UTC); 142 | 143 | assertClockInstant(mockClock, DATE_ONLY_INSTANT); 144 | } 145 | 146 | @Test 147 | public void adjustWithInstant() { 148 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 149 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, 9, 30, 13, 212, UTC).toInstant(); 150 | 151 | mockClock.set(adjustedInstant); 152 | 153 | assertClockInstant(mockClock, adjustedInstant); 154 | } 155 | 156 | @Test 157 | public void adjustWithLocalDateTime() { 158 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 159 | LocalDateTime adjustedLocalDateTime = LocalDateTime.of(2016, 1, 4, 9, 30, 13, 212); 160 | Instant adjustedInstant = ZonedDateTime.of(adjustedLocalDateTime, UTC).toInstant(); 161 | 162 | mockClock.set(adjustedLocalDateTime); 163 | 164 | assertClockInstant(mockClock, adjustedInstant); 165 | } 166 | 167 | @Test 168 | public void adjustWithLocalDateAndLocalTime() { 169 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 170 | LocalDate adjustedLocalDate = LocalDate.of(2016, 1, 4); 171 | LocalTime adjustedLocalTime = LocalTime.of(9, 30, 13, 212); 172 | Instant adjustedInstant = ZonedDateTime.of(adjustedLocalDate, adjustedLocalTime, UTC).toInstant(); 173 | 174 | mockClock.set(adjustedLocalDate, adjustedLocalTime); 175 | 176 | assertClockInstant(mockClock, adjustedInstant); 177 | } 178 | 179 | @Test 180 | public void adjustWithLocalDateLeavingTimeUnchanged() { 181 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 182 | LocalDate adjustedLocalDate = LocalDate.of(2016, 1, 4); 183 | Instant adjustedInstant = ZonedDateTime.of(adjustedLocalDate, LOCAL_TIME, UTC).toInstant(); 184 | 185 | mockClock.set(adjustedLocalDate); 186 | 187 | assertClockInstant(mockClock, adjustedInstant); 188 | } 189 | 190 | @Test 191 | public void adjustWithLocalTimeLeavingDateUnchanged() { 192 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 193 | LocalTime adjustedLocalTime = LocalTime.of(9, 30, 13, 212); 194 | Instant adjustedInstant = ZonedDateTime.of(LOCAL_DATE, adjustedLocalTime, UTC).toInstant(); 195 | 196 | mockClock.set(adjustedLocalTime); 197 | 198 | assertClockInstant(mockClock, adjustedInstant); 199 | } 200 | 201 | @Test 202 | public void adjustWithFullDateAndTimeWithNanoResolution() { 203 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 204 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, 9, 30, 13, 212, UTC).toInstant(); 205 | 206 | mockClock.set(2016, JANUARY, 4, 9, 30, 13, 212); 207 | 208 | assertClockInstant(mockClock, adjustedInstant); 209 | } 210 | 211 | @Test 212 | public void adjustWithFullDateAndTimeWithSecondResolutionLeavingNanoUnchanged() { 213 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 214 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, 9, 30, 13, NANO_OF_SECOND, UTC).toInstant(); 215 | 216 | mockClock.set(2016, JANUARY, 4, 9, 30, 13); 217 | 218 | assertClockInstant(mockClock, adjustedInstant); 219 | } 220 | 221 | @Test 222 | public void adjustWithFullDateAndTimeWithMinuteResolutionLeavingSecondAndNanoUnchanged() { 223 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 224 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, 9, 30, SECOND, NANO_OF_SECOND, UTC).toInstant(); 225 | 226 | mockClock.set(2016, JANUARY, 4, 9, 30); 227 | 228 | assertClockInstant(mockClock, adjustedInstant); 229 | } 230 | 231 | @Test 232 | public void adjustWithFullDateLeavingTimeUnchanged() { 233 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 234 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 235 | 236 | mockClock.set(2016, JANUARY, 4); 237 | 238 | assertClockInstant(mockClock, adjustedInstant); 239 | } 240 | 241 | @Test 242 | public void adjustWithFullDateAndTimeWithIntegerMonthAndNanoResolution() { 243 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 244 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, 9, 30, 13, 212, UTC).toInstant(); 245 | 246 | mockClock.set(2016, 1, 4, 9, 30, 13, 212); 247 | 248 | assertClockInstant(mockClock, adjustedInstant); 249 | } 250 | 251 | @Test 252 | public void adjustWithFullDateAndTimeWithIntegerMonthAndSecondResolutionLeavingNanoUnchanged() { 253 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 254 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, 9, 30, 13, NANO_OF_SECOND, UTC).toInstant(); 255 | 256 | mockClock.set(2016, 1, 4, 9, 30, 13); 257 | 258 | assertClockInstant(mockClock, adjustedInstant); 259 | } 260 | 261 | @Test 262 | public void adjustWithFullDateAndTimeWithIntegerMonthAndMinuteResolutionLeavingSecondAndNanoUnchanged() { 263 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 264 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, 9, 30, SECOND, NANO_OF_SECOND, UTC).toInstant(); 265 | 266 | mockClock.set(2016, 1, 4, 9, 30); 267 | 268 | assertClockInstant(mockClock, adjustedInstant); 269 | } 270 | 271 | @Test 272 | public void adjustWithFullDateAndIntegerMonthLeavingTimeUnchanged() { 273 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 274 | Instant adjustedInstant = ZonedDateTime.of(2016, 1, 4, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 275 | 276 | mockClock.set(2016, 1, 4); 277 | 278 | assertClockInstant(mockClock, adjustedInstant); 279 | } 280 | 281 | @Test 282 | public void adjustWithYear() { 283 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 284 | Instant adjustedInstant = ZonedDateTime 285 | .of(2017, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 286 | 287 | mockClock.setYear(2017); 288 | 289 | assertClockInstant(mockClock, adjustedInstant); 290 | } 291 | 292 | @Test 293 | public void adjustWithMonth() { 294 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 295 | Instant adjustedInstant = ZonedDateTime 296 | .of(YEAR, JANUARY.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 297 | 298 | mockClock.setMonth(JANUARY); 299 | 300 | assertClockInstant(mockClock, adjustedInstant); 301 | } 302 | 303 | @Test 304 | public void adjustWithIntegerMonth() { 305 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 306 | Instant adjustedInstant = ZonedDateTime 307 | .of(YEAR, JANUARY.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 308 | 309 | mockClock.setMonth(1); 310 | 311 | assertClockInstant(mockClock, adjustedInstant); 312 | } 313 | 314 | @Test 315 | public void adjustWithDayOfMonth() { 316 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 317 | Instant adjustedInstant = ZonedDateTime 318 | .of(YEAR, MONTH.getValue(), 17, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 319 | 320 | mockClock.setDayOfMonth(17); 321 | 322 | assertClockInstant(mockClock, adjustedInstant); 323 | } 324 | 325 | @Test 326 | public void adjustWithHour() { 327 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 328 | Instant adjustedInstant = ZonedDateTime 329 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, 9, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 330 | 331 | mockClock.setHour(9); 332 | 333 | assertClockInstant(mockClock, adjustedInstant); 334 | } 335 | 336 | @Test 337 | public void adjustWithMinute() { 338 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 339 | Instant adjustedInstant = ZonedDateTime 340 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, 30, SECOND, NANO_OF_SECOND, UTC).toInstant(); 341 | 342 | mockClock.setMinute(30); 343 | 344 | assertClockInstant(mockClock, adjustedInstant); 345 | } 346 | 347 | @Test 348 | public void adjustWithSecond() { 349 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 350 | Instant adjustedInstant = ZonedDateTime 351 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, 13, NANO_OF_SECOND, UTC).toInstant(); 352 | 353 | mockClock.setSecond(13); 354 | 355 | assertClockInstant(mockClock, adjustedInstant); 356 | } 357 | 358 | @Test 359 | public void adjustWithMilli() { 360 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 361 | int nanoOfSecond = 400_000_000; 362 | Instant adjustedInstant = ZonedDateTime.of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND, 363 | nanoOfSecond, UTC).toInstant(); 364 | 365 | mockClock.setMilli(400); 366 | 367 | assertClockInstant(mockClock, adjustedInstant); 368 | } 369 | 370 | @Test 371 | public void adjustWithNano() { 372 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 373 | Instant adjustedInstant = ZonedDateTime.of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND, 212, UTC) 374 | .toInstant(); 375 | 376 | mockClock.setNano(212); 377 | 378 | assertClockInstant(mockClock, adjustedInstant); 379 | } 380 | 381 | @Test 382 | public void advanceByDuration() { 383 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 384 | Instant adjustedInstant = ZonedDateTime 385 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND + 10, NANO_OF_SECOND, UTC).toInstant(); 386 | 387 | mockClock.advanceBy(Duration.ofSeconds(10)); 388 | 389 | assertClockInstant(mockClock, adjustedInstant); 390 | } 391 | 392 | @Test 393 | public void advanceByDays() { 394 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 395 | Instant adjustedInstant = ZonedDateTime 396 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH + 3, HOUR, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 397 | 398 | mockClock.advanceByDays(3); 399 | 400 | assertClockInstant(mockClock, adjustedInstant); 401 | } 402 | 403 | @Test 404 | public void advanceByHours() { 405 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 406 | Instant adjustedInstant = ZonedDateTime 407 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR + 2, MINUTE, SECOND, NANO_OF_SECOND, UTC).toInstant(); 408 | 409 | mockClock.advanceByHours(2); 410 | 411 | assertClockInstant(mockClock, adjustedInstant); 412 | } 413 | 414 | @Test 415 | public void advanceByMinutes() { 416 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 417 | Instant adjustedInstant = ZonedDateTime 418 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE + 4, SECOND, NANO_OF_SECOND, UTC).toInstant(); 419 | 420 | mockClock.advanceByMinutes(4); 421 | 422 | assertClockInstant(mockClock, adjustedInstant); 423 | } 424 | 425 | @Test 426 | public void advanceBySeconds() { 427 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 428 | Instant adjustedInstant = ZonedDateTime 429 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND + 5, NANO_OF_SECOND, UTC).toInstant(); 430 | 431 | mockClock.advanceBySeconds(5); 432 | 433 | assertClockInstant(mockClock, adjustedInstant); 434 | } 435 | 436 | @Test 437 | public void advanceByMillis() { 438 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 439 | int nanoOfSecond = NANO_OF_SECOND + 400_000_000; 440 | Instant adjustedInstant = ZonedDateTime 441 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND, nanoOfSecond, UTC).toInstant(); 442 | 443 | mockClock.advanceByMillis(400); 444 | 445 | assertClockInstant(mockClock, adjustedInstant); 446 | } 447 | 448 | @Test 449 | public void advanceByNanos() { 450 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 451 | Instant adjustedInstant = ZonedDateTime 452 | .of(YEAR, MONTH.getValue(), DAY_OF_MONTH, HOUR, MINUTE, SECOND, NANO_OF_SECOND + 1000, UTC).toInstant(); 453 | 454 | mockClock.advanceByNanos(1000); 455 | 456 | assertClockInstant(mockClock, adjustedInstant); 457 | } 458 | 459 | @Test 460 | public void withZoneCopyHasSameInstantButDifferentZone() { 461 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 462 | ZoneId cet = ZoneId.of("CET"); 463 | 464 | MockClock copied = mockClock.withZone(cet); 465 | 466 | assertClockInstant(copied, DATE_TIME_INSTANT, cet); 467 | } 468 | 469 | @Test 470 | public void sameConstructorParametersYieldEqualInstances() { 471 | MockClock mockClock1 = MockClock.at(DATE_TIME_INSTANT, UTC); 472 | MockClock mockClock2 = MockClock.at(DATE_TIME_INSTANT, UTC); 473 | 474 | assertThat(mockClock1.equals(mockClock2), is(true)); 475 | } 476 | 477 | @Test 478 | public void sameInstancesAreEqual() { 479 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 480 | 481 | assertThat(mockClock.equals(mockClock), is(true)); 482 | } 483 | 484 | @Test 485 | public void nullInstanceIsNotEqual() { 486 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 487 | 488 | assertThat(mockClock.equals(null), is(false)); 489 | } 490 | 491 | @Test 492 | public void instanceOfDifferentClassIsNotEqual() { 493 | MockClock mockClock = MockClock.at(DATE_TIME_INSTANT, UTC); 494 | 495 | assertThat(mockClock.equals(Clock.systemUTC()), is(false)); 496 | } 497 | 498 | @Test 499 | public void clockWithDifferentInstantIsNotEqual() { 500 | MockClock mockClock1 = MockClock.at(DATE_TIME_INSTANT, UTC); 501 | MockClock mockClock2 = MockClock.at(DATE_ONLY_INSTANT, UTC); 502 | 503 | assertThat(mockClock1.equals(mockClock2), is(false)); 504 | } 505 | 506 | @Test 507 | public void clockWithDifferentZoneIsNotEqual() { 508 | MockClock mockClock1 = MockClock.at(DATE_TIME_INSTANT, UTC); 509 | MockClock mockClock2 = MockClock.at(DATE_TIME_INSTANT, ZoneId.of("CET")); 510 | 511 | assertThat(mockClock1.equals(mockClock2), is(false)); 512 | } 513 | 514 | @Test 515 | public void sameConstructorParametersYieldEqualHashCodes() { 516 | MockClock mockClock1 = MockClock.at(DATE_TIME_INSTANT, UTC); 517 | MockClock mockClock2 = MockClock.at(DATE_TIME_INSTANT, UTC); 518 | 519 | assertThat(mockClock1.hashCode(), is(mockClock2.hashCode())); 520 | } 521 | 522 | @Test 523 | public void sameConstructorParametersYieldEqualStringRepresentations() { 524 | MockClock mockClock1 = MockClock.at(DATE_TIME_INSTANT, UTC); 525 | MockClock mockClock2 = MockClock.at(DATE_TIME_INSTANT, UTC); 526 | 527 | assertThat(mockClock1.toString(), is(mockClock2.toString())); 528 | } 529 | 530 | private void assertClockInstant(MockClock mockClock, Instant instant) { 531 | assertClockInstant(mockClock, instant, UTC); 532 | } 533 | 534 | private void assertClockInstant(MockClock mockClock, Instant instant, ZoneId zone) { 535 | assertThat(mockClock.instant(), is(instant)); 536 | assertThat(mockClock.getZone(), is(zone)); 537 | } 538 | } 539 | -------------------------------------------------------------------------------- /src/main/java/com/statemachinesystems/mockclock/MockClock.java: -------------------------------------------------------------------------------- 1 | package com.statemachinesystems.mockclock; 2 | 3 | import java.time.Clock; 4 | import java.time.Duration; 5 | import java.time.Instant; 6 | import java.time.LocalDate; 7 | import java.time.LocalDateTime; 8 | import java.time.LocalTime; 9 | import java.time.Month; 10 | import java.time.ZoneId; 11 | import java.time.ZonedDateTime; 12 | import java.util.Objects; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | /** 16 | * Mutable implementation of {@link java.time.Clock} for testing. 17 | */ 18 | public class MockClock extends Clock { 19 | 20 | /** 21 | * Construct a {@link MockClock} using the current time in the given zone. 22 | * 23 | * @param zone the zone to use 24 | * @return a {@link MockClock} instance initially set to the current time in the given zone 25 | */ 26 | public static MockClock now(ZoneId zone) { 27 | return at(Clock.system(zone)); 28 | } 29 | 30 | /** 31 | * Construct a {@link MockClock} using the current time according to the given clock. 32 | * 33 | * @param clock the clock to use 34 | * @return a {@link MockClock} instance initially set to the current time according to the given clock 35 | */ 36 | public static MockClock at(Clock clock) { 37 | Objects.requireNonNull(clock, "clock"); 38 | return new MockClock(clock.instant(), clock.getZone()); 39 | } 40 | 41 | /** 42 | * Construct a {@link MockClock} using the given {@link Instant} and zone. 43 | * 44 | * @param instant the {@link Instant} to use 45 | * @param zone the zone to use 46 | * @return a {@link MockClock} instance initially set to the given {@link Instant} and zone 47 | */ 48 | public static MockClock at(Instant instant, ZoneId zone) { 49 | Objects.requireNonNull(instant, "instant"); 50 | Objects.requireNonNull(zone, "zone"); 51 | return new MockClock(instant, zone); 52 | } 53 | 54 | /** 55 | * Construct a {@link MockClock} using the given {@link ZonedDateTime}. 56 | * 57 | * @param zonedDateTime the {@link ZonedDateTime} to use 58 | * @return a {@link MockClock} instance initially set to the given {@link ZonedDateTime} 59 | */ 60 | public static MockClock at(ZonedDateTime zonedDateTime) { 61 | Objects.requireNonNull(zonedDateTime, "zonedDateTime"); 62 | return at(zonedDateTime.toInstant(), zonedDateTime.getZone()); 63 | } 64 | 65 | /** 66 | * Construct a {@link MockClock} using the given {@link LocalDateTime} and zone. 67 | * 68 | * @param localDateTime the {@link LocalDateTime} to use 69 | * @param zone the zone to use 70 | * @return a {@link MockClock} instance initially set to the given {@link LocalDateTime} and zone 71 | */ 72 | public static MockClock at(LocalDateTime localDateTime, ZoneId zone) { 73 | Objects.requireNonNull(localDateTime, "localDateTime"); 74 | Objects.requireNonNull(zone, "zone"); 75 | return at(localDateTime.atZone(zone)); 76 | } 77 | 78 | /** 79 | * Construct a {@link MockClock} using the given date and zone. 80 | * 81 | * @param localDate the date to use 82 | * @param zone the zone to use 83 | * @return a {@link MockClock} instance initially set to the given date and zone 84 | */ 85 | public static MockClock at(LocalDate localDate, ZoneId zone) { 86 | Objects.requireNonNull(localDate, "localDate"); 87 | Objects.requireNonNull(zone, "zone"); 88 | return at(localDate.atStartOfDay(zone)); 89 | } 90 | 91 | /** 92 | * Construct a {@link MockClock} using the given date, time and zone. 93 | * 94 | * @param localDate the date to use 95 | * @param localTime the time to use 96 | * @param zone the zone to use 97 | * @return a {@link MockClock} instance initially set to the given date, time and zone 98 | */ 99 | public static MockClock at(LocalDate localDate, LocalTime localTime, ZoneId zone) { 100 | Objects.requireNonNull(localDate, "localDate"); 101 | Objects.requireNonNull(localTime, "localTime"); 102 | Objects.requireNonNull(zone, "zone"); 103 | return at(LocalDateTime.of(localDate, localTime), zone); 104 | } 105 | 106 | /** 107 | * Construct a {@link MockClock} using the given year, month, day of month, hour, minute, second, nanosecond and 108 | * zone. 109 | * 110 | * @param year the year to use 111 | * @param month the month to use 112 | * @param dayOfMonth the day of month to use 113 | * @param hour the hour to use 114 | * @param minute the minute to use 115 | * @param second the second to use 116 | * @param nanoOfSecond the nanosecond to use 117 | * @param zone the zone to use 118 | * @return a {@link MockClock} instance initially set to the given year, month, day of month, hour, minute, second, 119 | * nanosecond and zone 120 | */ 121 | public static MockClock at(int year, Month month, int dayOfMonth, int hour, int minute, int second, 122 | int nanoOfSecond, ZoneId zone) { 123 | Objects.requireNonNull(month, "month"); 124 | Objects.requireNonNull(zone, "zone"); 125 | return at(LocalDate.of(year, month, dayOfMonth), LocalTime.of(hour, minute, second, nanoOfSecond), zone); 126 | } 127 | 128 | /** 129 | * Construct a {@link MockClock} using the given year, month, day of month, hour, minute, second and zone. 130 | * 131 | * @param year the year to use 132 | * @param month the month to use 133 | * @param dayOfMonth the day of month to use 134 | * @param hour the hour to use 135 | * @param minute the minute to use 136 | * @param second the second to use 137 | * @param zone the zone to use 138 | * @return a {@link MockClock} instance initially set to the given year, month, day of month, hour, minute, second 139 | * and zone 140 | */ 141 | public static MockClock at(int year, Month month, int dayOfMonth, int hour, int minute, int second, ZoneId zone) { 142 | Objects.requireNonNull(month, "month"); 143 | Objects.requireNonNull(zone, "zone"); 144 | return at(LocalDate.of(year, month, dayOfMonth), LocalTime.of(hour, minute, second), zone); 145 | } 146 | 147 | /** 148 | * Construct a {@link MockClock} using the given year, month, day of month, hour, minute and zone. 149 | * 150 | * @param year the year to use 151 | * @param month the month to use 152 | * @param dayOfMonth the day of month to use 153 | * @param hour the hour to use 154 | * @param minute the minute to use 155 | * @param zone the zone to use 156 | * @return a {@link MockClock} instance initially set to the given year, month, day of month, hour, minute and zone 157 | */ 158 | public static MockClock at(int year, Month month, int dayOfMonth, int hour, int minute, ZoneId zone) { 159 | Objects.requireNonNull(month, "month"); 160 | Objects.requireNonNull(zone, "zone"); 161 | return at(LocalDate.of(year, month, dayOfMonth), LocalTime.of(hour, minute), zone); 162 | } 163 | 164 | /** 165 | * Construct a {@link MockClock} using the given year, month, day of month and zone. 166 | * 167 | * @param year the year to use 168 | * @param month the month to use 169 | * @param dayOfMonth the day of month to use 170 | * @param zone the zone to use 171 | * @return a {@link MockClock} instance initially set to the given year, month, day of month and zone 172 | */ 173 | public static MockClock at(int year, Month month, int dayOfMonth, ZoneId zone) { 174 | Objects.requireNonNull(month, "month"); 175 | Objects.requireNonNull(zone, "zone"); 176 | return at(LocalDate.of(year, month, dayOfMonth), zone); 177 | } 178 | 179 | /** 180 | * Construct a {@link MockClock} using the given year, month, day of month, hour, minute, second, nanosecond and 181 | * zone. 182 | * 183 | * @param year the year to use 184 | * @param month the month to use 185 | * @param dayOfMonth the day of month to use 186 | * @param hour the hour to use 187 | * @param minute the minute to use 188 | * @param second the second to use 189 | * @param nanoOfSecond the nanosecond to use 190 | * @param zone the zone to use 191 | * @return a {@link MockClock} instance initially set to the given year, month, day of month, hour, minute, second, 192 | * nanosecond and zone 193 | */ 194 | public static MockClock at(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, 195 | ZoneId zone) { 196 | Objects.requireNonNull(zone, "zone"); 197 | return at(LocalDate.of(year, month, dayOfMonth), LocalTime.of(hour, minute, second, nanoOfSecond), zone); 198 | } 199 | 200 | /** 201 | * Construct a {@link MockClock} using the given year, month, day of month, hour, minute, second and zone. 202 | * 203 | * @param year the year to use 204 | * @param month the month to use 205 | * @param dayOfMonth the day of month to use 206 | * @param hour the hour to use 207 | * @param minute the minute to use 208 | * @param second the second to use 209 | * @param zone the zone to use 210 | * @return a {@link MockClock} instance initially set to the given year, month, day of month, hour, minute, second 211 | * and zone 212 | */ 213 | public static MockClock at(int year, int month, int dayOfMonth, int hour, int minute, int second, ZoneId zone) { 214 | Objects.requireNonNull(zone, "zone"); 215 | return at(LocalDate.of(year, month, dayOfMonth), LocalTime.of(hour, minute, second), zone); 216 | } 217 | 218 | /** 219 | * Construct a {@link MockClock} using the given year, month, day of month, hour, minute and zone. 220 | * 221 | * @param year the year to use 222 | * @param month the month to use 223 | * @param dayOfMonth the day of month to use 224 | * @param hour the hour to use 225 | * @param minute the minute to use 226 | * @param zone the zone to use 227 | * @return a {@link MockClock} instance initially set to the given year, month, day of month, hour, minute and zone 228 | */ 229 | public static MockClock at(int year, int month, int dayOfMonth, int hour, int minute, ZoneId zone) { 230 | Objects.requireNonNull(zone, "zone"); 231 | return at(LocalDate.of(year, month, dayOfMonth), LocalTime.of(hour, minute), zone); 232 | } 233 | 234 | /** 235 | * Construct a {@link MockClock} using the given year, month, day of month and zone. 236 | * 237 | * @param year the year to use 238 | * @param month the month to use 239 | * @param dayOfMonth the day of month to use 240 | * @param zone the zone to use 241 | * @return a {@link MockClock} instance initially set to the given year, month, day of month and zone 242 | */ 243 | public static MockClock at(int year, int month, int dayOfMonth, ZoneId zone) { 244 | Objects.requireNonNull(zone, "zone"); 245 | return at(LocalDate.of(year, month, dayOfMonth), zone); 246 | } 247 | 248 | private Instant instant; 249 | private final ZoneId zone; 250 | 251 | private MockClock(Instant instant, ZoneId zone) { 252 | this.instant = instant; 253 | this.zone = zone; 254 | } 255 | 256 | /** 257 | * Set the clock's date and time to the given {@link Instant}. 258 | * 259 | * @param instant the {@link Instant} to use 260 | * @return this {@link MockClock} instance 261 | */ 262 | public MockClock set(Instant instant) { 263 | Objects.requireNonNull(instant, "instant"); 264 | this.instant = instant; 265 | return this; 266 | } 267 | 268 | /** 269 | * Set the clock's date and time using the given {@link LocalDateTime}. 270 | * 271 | * @param localDateTime the {@link LocalDateTime} to use 272 | * @return this {@link MockClock} instance 273 | */ 274 | public MockClock set(LocalDateTime localDateTime) { 275 | Objects.requireNonNull(localDateTime, "localDateTime"); 276 | this.instant = localDateTime.atZone(zone).toInstant(); 277 | return this; 278 | } 279 | 280 | /** 281 | * Set the clock's date and time using the given {@link LocalDate} and {@link LocalTime}. 282 | * 283 | * @param localDate the {@link LocalDate} to use 284 | * @param localTime the {@link LocalTime} to use 285 | * @return this {@link MockClock} instance 286 | */ 287 | public MockClock set(LocalDate localDate, LocalTime localTime) { 288 | Objects.requireNonNull(localDate, "localDate"); 289 | Objects.requireNonNull(localTime, "localTime"); 290 | this.instant = ZonedDateTime.of(localDate, localTime, zone).toInstant(); 291 | return this; 292 | } 293 | 294 | /** 295 | * Set the clock's date using the given {@link LocalDate}, retaining the current time. 296 | * 297 | * @param localDate the {@link LocalDate} to use 298 | * @return this {@link MockClock} instance 299 | */ 300 | public MockClock set(LocalDate localDate) { 301 | Objects.requireNonNull(localDate, "localDate"); 302 | LocalTime localTime = toZonedDateTime().toLocalTime(); 303 | this.instant = ZonedDateTime.of(localDate, localTime, zone).toInstant(); 304 | return this; 305 | } 306 | 307 | /** 308 | * Set the clock's time using the given {@link LocalTime}, retaining the current date. 309 | * 310 | * @param localTime the {@link LocalTime} to use 311 | * @return this {@link MockClock} instance 312 | */ 313 | public MockClock set(LocalTime localTime) { 314 | Objects.requireNonNull(localTime, "localTime"); 315 | LocalDate localDate = toZonedDateTime().toLocalDate(); 316 | this.instant = ZonedDateTime.of(localDate, localTime, zone).toInstant(); 317 | return this; 318 | } 319 | 320 | /** 321 | * Set the clock's date and time using the given year, month, day of month, hour, minute, second and nanosecond. 322 | * 323 | * @param year the year to use 324 | * @param month the month to use 325 | * @param dayOfMonth the day of month to use 326 | * @param hour the hour to use 327 | * @param minute the minute to use 328 | * @param second the second to use 329 | * @param nanoOfSecond the nanosecond to use 330 | * @return this {@link MockClock} instance 331 | */ 332 | public MockClock set(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) { 333 | Objects.requireNonNull(month, "month"); 334 | ZonedDateTime zonedDateTime = ZonedDateTime 335 | .of(year, month.getValue(), dayOfMonth, hour, minute, second, nanoOfSecond, zone); 336 | this.instant = zonedDateTime.toInstant(); 337 | return this; 338 | } 339 | 340 | /** 341 | * Set the clock's date and time using the given year, month, day of month, hour, minute and second, retaining the 342 | * current nanosecond. 343 | * 344 | * @param year the year to use 345 | * @param month the month to use 346 | * @param dayOfMonth the day of month to use 347 | * @param hour the hour to use 348 | * @param minute the minute to use 349 | * @param second the second to use 350 | * @return this {@link MockClock} instance 351 | */ 352 | public MockClock set(int year, Month month, int dayOfMonth, int hour, int minute, int second) { 353 | int nanoOfSecond = toZonedDateTime().getNano(); 354 | return set(year, month, dayOfMonth, hour, minute, second, nanoOfSecond); 355 | } 356 | 357 | /** 358 | * Set the clock's date and time using the given year, month, day of month, hour and minute, retaining the 359 | * current second and nanosecond. 360 | * 361 | * @param year the year to use 362 | * @param month the month to use 363 | * @param dayOfMonth the day of month to use 364 | * @param hour the hour to use 365 | * @param minute the minute to use 366 | * @return this {@link MockClock} instance 367 | */ 368 | public MockClock set(int year, Month month, int dayOfMonth, int hour, int minute) { 369 | ZonedDateTime zonedDateTime = toZonedDateTime(); 370 | int second = zonedDateTime.getSecond(); 371 | int nanoOfSecond = zonedDateTime.getNano(); 372 | return set(year, month, dayOfMonth, hour, minute, second, nanoOfSecond); 373 | } 374 | 375 | /** 376 | * Set the clock's date using the given year, month and day of month, retaining the current time. 377 | * 378 | * @param year the year to use 379 | * @param month the month to use 380 | * @param dayOfMonth the day of month to use 381 | * @return this {@link MockClock} instance 382 | */ 383 | public MockClock set(int year, Month month, int dayOfMonth) { 384 | ZonedDateTime zonedDateTime = toZonedDateTime(); 385 | int hour = zonedDateTime.getHour(); 386 | int minute = zonedDateTime.getMinute(); 387 | int second = zonedDateTime.getSecond(); 388 | int nanoOfSecond = zonedDateTime.getNano(); 389 | return set(year, month, dayOfMonth, hour, minute, second, nanoOfSecond); 390 | } 391 | 392 | /** 393 | * Set the clock's date and time using the given year, month, day of month, hour, minute, second and nanosecond. 394 | * 395 | * @param year the year to use 396 | * @param month the month to use 397 | * @param dayOfMonth the day of month to use 398 | * @param hour the hour to use 399 | * @param minute the minute to use 400 | * @param second the second to use 401 | * @param nanoOfSecond the nanosecond to use 402 | * @return this {@link MockClock} instance 403 | */ 404 | public MockClock set(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) { 405 | return set(year, Month.of(month), dayOfMonth, hour, minute, second, nanoOfSecond); 406 | } 407 | 408 | /** 409 | * Set the clock's date and time using the given year, month, day of month, hour, minute and second, retaining the 410 | * current nanosecond. 411 | * 412 | * @param year the year to use 413 | * @param month the month to use 414 | * @param dayOfMonth the day of month to use 415 | * @param hour the hour to use 416 | * @param minute the minute to use 417 | * @param second the second to use 418 | * @return this {@link MockClock} instance 419 | */ 420 | public MockClock set(int year, int month, int dayOfMonth, int hour, int minute, int second) { 421 | return set(year, Month.of(month), dayOfMonth, hour, minute, second); 422 | } 423 | 424 | /** 425 | * Set the clock's date and time using the given year, month, day of month, hour and minute, retaining the 426 | * current second and nanosecond. 427 | * 428 | * @param year the year to use 429 | * @param month the month to use 430 | * @param dayOfMonth the day of month to use 431 | * @param hour the hour to use 432 | * @param minute the minute to use 433 | * @return this {@link MockClock} instance 434 | */ 435 | public MockClock set(int year, int month, int dayOfMonth, int hour, int minute) { 436 | return set(year, Month.of(month), dayOfMonth, hour, minute); 437 | } 438 | 439 | /** 440 | * Set the clock's date using the given year, month and day of month, retaining the current time. 441 | * 442 | * @param year the year to use 443 | * @param month the month to use 444 | * @param dayOfMonth the day of month to use 445 | * @return this {@link MockClock} instance 446 | */ 447 | public MockClock set(int year, int month, int dayOfMonth) { 448 | return set(year, Month.of(month), dayOfMonth); 449 | } 450 | 451 | /** 452 | * Set the clock's year only, retaining all other date and time components. 453 | * 454 | * @param year the year to use 455 | * @return this {@link MockClock} instance 456 | */ 457 | public MockClock setYear(int year) { 458 | this.instant = toZonedDateTime().withYear(year).toInstant(); 459 | return this; 460 | } 461 | 462 | /** 463 | * Set the clock's month only, retaining all other date and time components. 464 | * 465 | * @param month the month to use 466 | * @return this {@link MockClock} instance 467 | */ 468 | public MockClock setMonth(Month month) { 469 | return setMonth(month.getValue()); 470 | } 471 | 472 | /** 473 | * Set the clock's month only, retaining all other date and time components. 474 | * 475 | * @param month the month to use 476 | * @return this {@link MockClock} instance 477 | */ 478 | public MockClock setMonth(int month) { 479 | this.instant = toZonedDateTime().withMonth(month).toInstant(); 480 | return this; 481 | } 482 | 483 | /** 484 | * Set the clock's day of month only, retaining all other date and time components. 485 | * 486 | * @param dayOfMonth the day of month to use 487 | * @return this {@link MockClock} instance 488 | */ 489 | public MockClock setDayOfMonth(int dayOfMonth) { 490 | this.instant = toZonedDateTime().withDayOfMonth(dayOfMonth).toInstant(); 491 | return this; 492 | } 493 | 494 | /** 495 | * Set the clock's hour only, retaining all other date and time components. 496 | * 497 | * @param hour the hour to use 498 | * @return this {@link MockClock} instance 499 | */ 500 | public MockClock setHour(int hour) { 501 | this.instant = toZonedDateTime().withHour(hour).toInstant(); 502 | return this; 503 | } 504 | 505 | /** 506 | * Set the clock's minute only, retaining all other date and time components. 507 | * 508 | * @param minute the minute to use 509 | * @return this {@link MockClock} instance 510 | */ 511 | public MockClock setMinute(int minute) { 512 | this.instant = toZonedDateTime().withMinute(minute).toInstant(); 513 | return this; 514 | } 515 | 516 | /** 517 | * Set the clock's second only, retaining all other date and time components. 518 | * 519 | * @param second the second to use 520 | * @return this {@link MockClock} instance 521 | */ 522 | public MockClock setSecond(int second) { 523 | this.instant = toZonedDateTime().withSecond(second).toInstant(); 524 | return this; 525 | } 526 | 527 | /** 528 | * Set the clock's millisecond only, retaining all other date and time components. 529 | * 530 | * @param milliOfSecond the millisecond to use 531 | * @return this {@link MockClock} instance 532 | */ 533 | public MockClock setMilli(int milliOfSecond) { 534 | int nanoOfSecond = (int) TimeUnit.MILLISECONDS.toNanos(milliOfSecond); 535 | return setNano(nanoOfSecond); 536 | } 537 | 538 | /** 539 | * Set the clock's nanosecond only, retaining all other date and time components. 540 | * 541 | * @param nanoOfSecond the nanosecond to use 542 | * @return this {@link MockClock} instance 543 | */ 544 | public MockClock setNano(int nanoOfSecond) { 545 | this.instant = toZonedDateTime().withNano(nanoOfSecond).toInstant(); 546 | return this; 547 | } 548 | 549 | /** 550 | * Advance the clock by the given {@link Duration}. 551 | * 552 | * @param duration the duration by which to advance 553 | * @return this {@link MockClock} instance 554 | */ 555 | public MockClock advanceBy(Duration duration) { 556 | this.instant = toZonedDateTime().plus(duration).toInstant(); 557 | return this; 558 | } 559 | 560 | /** 561 | * Advance the clock by the given number of days (represented as 24 hours.) 562 | * 563 | * @param days the number of days by which to advance 564 | * @return this {@link MockClock} instance 565 | */ 566 | public MockClock advanceByDays(int days) { 567 | return advanceBy(Duration.ofDays(days)); 568 | } 569 | 570 | /** 571 | * Advance the clock by the given number of hours. 572 | * 573 | * @param hours the number of hours by which to advance 574 | * @return this {@link MockClock} instance 575 | */ 576 | public MockClock advanceByHours(int hours) { 577 | return advanceBy(Duration.ofHours(hours)); 578 | } 579 | 580 | /** 581 | * Advance the clock by the given number of minutes. 582 | * 583 | * @param minutes the number of minutes by which to advance 584 | * @return this {@link MockClock} instance 585 | */ 586 | public MockClock advanceByMinutes(int minutes) { 587 | return advanceBy(Duration.ofMinutes(minutes)); 588 | } 589 | 590 | /** 591 | * Advance the clock by the given number of seconds. 592 | * 593 | * @param seconds the number of seconds by which to advance 594 | * @return this {@link MockClock} instance 595 | */ 596 | public MockClock advanceBySeconds(int seconds) { 597 | return advanceBy(Duration.ofSeconds(seconds)); 598 | } 599 | 600 | /** 601 | * Advance the clock by the given number of milliseconds. 602 | * 603 | * @param millis the number of milliseconds by which to advance 604 | * @return this {@link MockClock} instance 605 | */ 606 | public MockClock advanceByMillis(int millis) { 607 | return advanceBy(Duration.ofMillis(millis)); 608 | } 609 | 610 | /** 611 | * Advance the clock by the given number of nanoseconds. 612 | * 613 | * @param nanos the number of nanoseconds by which to advance 614 | * @return this {@link MockClock} instance 615 | */ 616 | public MockClock advanceByNanos(int nanos) { 617 | return advanceBy(Duration.ofNanos(nanos)); 618 | } 619 | 620 | /** 621 | * Retrieve the clock's date and time as a {@link ZonedDateTime}. 622 | * 623 | * @return a {@link ZonedDateTime} representing the clock's current state 624 | */ 625 | public ZonedDateTime toZonedDateTime() { 626 | return ZonedDateTime.ofInstant(instant, zone); 627 | } 628 | 629 | @Override 630 | public ZoneId getZone() { 631 | return zone; 632 | } 633 | 634 | @Override 635 | public MockClock withZone(ZoneId zone) { 636 | Objects.requireNonNull(zone, "zone"); 637 | return new MockClock(instant, zone); 638 | } 639 | 640 | @Override 641 | public Instant instant() { 642 | return instant; 643 | } 644 | 645 | @Override 646 | public String toString() { 647 | return "MockClock[" + instant + "," + zone + "]"; 648 | } 649 | 650 | @Override 651 | public boolean equals(Object o) { 652 | if (this == o) { 653 | return true; 654 | } 655 | if (o == null || getClass() != o.getClass()) { 656 | return false; 657 | } 658 | 659 | MockClock mockClock = (MockClock) o; 660 | return Objects.equals(instant, mockClock.instant) && Objects.equals(zone, mockClock.zone); 661 | } 662 | 663 | @Override 664 | public int hashCode() { 665 | return Objects.hash(instant, zone); 666 | } 667 | } 668 | --------------------------------------------------------------------------------