Timecop.NodaTime
1.3.1
dotnet add package Timecop.NodaTime --version 1.3.1
NuGet\Install-Package Timecop.NodaTime -Version 1.3.1
<PackageReference Include="Timecop.NodaTime" Version="1.3.1" />
paket add Timecop.NodaTime --version 1.3.1
#r "nuget: Timecop.NodaTime, 1.3.1"
// Install Timecop.NodaTime as a Cake Addin #addin nuget:?package=Timecop.NodaTime&version=1.3.1 // Install Timecop.NodaTime as a Cake Tool #tool nuget:?package=Timecop.NodaTime&version=1.3.1
Timecop for NodaTime
Timecop.NodaTime is Timecop with the NodaTime interface.
Timecop targets .NET Standard 2.0, and supports NodaTime v3.
Timecop.NodaTime and Timecop have been inspired by the timecop Ruby gem.
Installation
You can install Timecop.NodaTime from NuGet using the .NET CLI:
dotnet add package Timecop.NodaTime
Basics and usage
To test with Timecop.NodaTime, your code must get the current time using either:
- The
NodaTime.IClock
interface - The static
NodaClock
class
Usage with the NodaTime.IClock
interface
Timecop.NodaTime allows to set up NodaTime's IClock
.
Here's how to use it:
- Pass the instance of
NodaTime.IClock
to your code as a method or a constructur parameter and use it to get the current instant - In your tests, configure the
NodaTimecop
instance and pass itsClock
property into the code under test - When running in production, pass the
IClock
implementaton that always returns the current instant, such asNodaTime.SystemClock
Here's an example:
string Greet(IClock clock, DateTimeZone zone)
{
var timeOfDay = clock.GetCurrentInstant().InZone(zone).Hour switch
{
>= 0 and < 6 => "night",
>= 6 and < 12 => "morning",
>= 12 and < 18 => "afternoon",
_ => "evening"
};
return $"Good {timeOfDay}!";
}
var zone = DateTimeZoneProviders.Tzdb["Europe/Kyiv"];
// freeze at 2pm Kyiv time:
using var tc = NodaTimecop.Frozen(o => o.At(14, 0, 0).InZone(zone));
Greet(tc.Clock, zone); // Good afternoon!
// travel to 8pm local time:
tc.TravelBy(Duration.FromHours(6));
Greet(tc.Clock, zone); // Good evening!
Usage with the NodaClock
class
NodaTimecop provides the static NodaClock
class that you can use instead of SystemClock.Instance to get the current instant. Despite NodaClock
being a static class, it is safe to use in tests that run in parallel as it uses AsyncLocal under the hood.
string Greet(DateTimeZone zone)
{
var timeOfDay = NodaClock.GetCurrentInstant().InZone(zone).Hour switch // Use NodaClock instead of SystemClock.Instance
{
>= 0 and < 6 => "night",
>= 6 and < 12 => "morning",
>= 12 and < 18 => "afternoon",
_ => "evening"
};
return $"Good {timeOfDay}!";
}
var zone = DateTimeZoneProviders.Tzdb["Europe/Kyiv"];
// freeze at 2pm Kyiv time:
using var tc = NodaTimecop.Frozen(o => o.At(14, 0, 0).InZone(zone));
Greet(zone); // Good afternoon!
// travel to 8pm local time:
tc.TravelBy(Duration.FromHours(6));
Greet(zone); // Good evening!
Available methods
NodaTimecop allows to manipulate time in any imaginable way. Use it to freeze time, travel in time, and resume the flow of time.
Freezing and resuming time
You can freeze the time so that it stops running for your tests until you call Resume
, Reset
, or dispose the NOdaTimecop
instance.
To freeze the time, use either an instance Freeze
or a static Frozen
method, both having the same set of overloads. Both methods have the same effect, however the static Frozen
creates an already frozen NodaTimecop
instance.
using var tc = NodaTimecop.Frozen(Instant.FromUtc(1990, 12, 2, 14, 38, 51));
NodaClock.GetCurrentInstant(); // 1990-12-02 14:38:51
Thread.Sleep(TimeSpan.FromSeconds(3));
NodaClock.GetCurrentInstant(); // 1990-12-02 14:38:51 - still the same value
tc.Resume();
Thread.Sleep(TimeSpan.FromSeconds(3));
NodaClock.GetCurrentInstant(); // 1990-12-02 14:38:54 - moved ~3 seconds forward
Freeze
and Frozen
have multiple overloads:
// freeze at the current instant:
var frozenAt = tc.Freeze();
// freeze at the specific instant:
var instant = Instant.FromUtc(1990, 12, 2, 14, 53, 27);
var frozenAt = tc.Freeze(instant);
// freeze at the specific ZonedDateTime:
ZonedDateTime zonedDateTime = new LocalDateTime(1990, 12, 2, 14, 38, 51).InUtc();
frozenAt = tc.Freeze(zonedDateTime);
// freeze at the specific date or time using a PointInTimeBuilder:
frozenAt = tc.Freeze(o => o.On(1990, 12, 2)
.At(14, 13, 51)
.InUtc());
Traveling in time
Use the TravelBy
method to travel forward and backward in time:
using var tc = NodaTimecop.Frozen(Instant.FromUtc(1990, 12, 2, 14, 38, 51));
tc.TravelBy(Duration.FromDays(1));
NodaClock.GetCurrentInstant(); // 1990-12-03 14:38:51 - one day in the future
Use the TravelTo
method to travel to the specific point in time:
// travel to the specific instant:
var instant = Instant.FromUtc(1990, 12, 2, 14, 53, 27);
traveledTo = tc.TravelTo(instant);
// travel to the specific ZonedDateTime:
ZonedDateTime zonedDateTime = new LocalDateTime(1990, 12, 2, 14, 38, 51).InUtc();
traveledTo = tc.TravelTo(zonedDateTime);
// travel to the specific point in time configured with a PointInTimeBuilder:
traveledTo = tc.TravelTo(o => o.On(1990, 12, 2)
.At(14, 13, 51)
.InUtc());
Using PointInTimeBuilder
Freeze
, Frozen
, and TravelTo
methods each accept a lambda that allows to configure the time with the PointInTimeBuilder
class.
Use PointInTimeBuilder
to construct an Instant from its components. When using At
and On
methods, always specify the time zone using InZone
or InUtc
methods.
// When only the date matters:
builder.On(1990, 12, 2).InUtc(); // will use the specified date and current time
// When only the time matters:
builder.At(14, 13, 51).InZone(zone); // will use the specified time and current date
// When neither the date nor time matters, but the Instant must be in the future or in the past:
builder.InTheFuture();
builder.InThePast();
License
NodaTimecop was created by Dmytro Khmara and is licensed under the MIT license.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- NodaTime (>= 3.0.0 && < 4.0.0)
- Timecop.Core (>= 4.2.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.