Dela via


Vad är TimeProvider?

System.TimeProvider är en abstraktion av tiden som ger en DateTimeOffset-typ av tidpunkt. Genom att använda TimeProviderser du till att koden är testbar och förutsägbar. TimeProvider introducerades i .NET 8 och är även tillgängligt för .NET Framework 4.7+ och .NET Standard 2.0 som ett NuGet-paket.

Klassen TimeProvider definierar följande funktioner:

Förvaltsimplementering

.NET tillhandahåller en implementering av TimeProvider via egenskapen TimeProvider.System med följande egenskaper:

I följande exempel visas hur du använder TimeProvider för att hämta aktuellt datum och tid:

Console.WriteLine($"Local: {TimeProvider.System.GetLocalNow()}");
Console.WriteLine($"Utc:   {TimeProvider.System.GetUtcNow()}");

/* This example produces output similar to the following:
 *
 * Local: 12/5/2024 10:41:14 AM -08:00
 * Utc:   12/5/2024 6:41:14 PM +00:00
*/
Console.WriteLine($"Local: {TimeProvider.System.GetLocalNow()}")
Console.WriteLine($"Utc:   {TimeProvider.System.GetUtcNow()}")

' This example produces output similar to the following
'
' Local: 12/5/2024 10:41:14 AM -08:00
' Utc:   12/5/2024 6:41:14 PM +00:00

I följande exempel visas hur du fångar upp förfluten tid med TimeProvider.GetTimestamp():

long stampStart = TimeProvider.System.GetTimestamp();
Console.WriteLine($"Starting timestamp: {stampStart}");

long stampEnd = TimeProvider.System.GetTimestamp();
Console.WriteLine($"Ending timestamp:   {stampEnd}");

Console.WriteLine($"Elapsed time: {TimeProvider.System.GetElapsedTime(stampStart, stampEnd)}");
Console.WriteLine($"Nanoseconds: {TimeProvider.System.GetElapsedTime(stampStart, stampEnd).TotalNanoseconds}"); 

/* This example produces output similar to the following:
 *
 * Starting timestamp: 55185546133
 * Ending timestamp:   55185549929
 * Elapsed time: 00:00:00.0003796
 * Nanoseconds: 379600
*/
Dim stampStart As Long = TimeProvider.System.GetTimestamp()
Console.WriteLine($"Starting timestamp: {stampStart}")

Dim stampEnd As Long = TimeProvider.System.GetTimestamp()
Console.WriteLine($"Ending timestamp:   {stampEnd}")

Console.WriteLine($"Elapsed time: {TimeProvider.System.GetElapsedTime(stampStart, stampEnd)}")
Console.WriteLine($"Nanoseconds: {TimeProvider.System.GetElapsedTime(stampStart, stampEnd).TotalNanoseconds}")

' This example produces output similar to the following:
'
' Starting timestamp: 55185546133
' Ending timestamp:   55185549929
' Elapsed time: 00:00:00.0003796
' Nanoseconds: 379600

Implementering av FakeTimeProvider

Microsoft.Extensions.TimeProvider.Testing NuGet-paketet tillhandahåller en kontrollbar TimeProvider implementering som är utformad för enhetstestning.

I följande lista beskrivs några av funktionerna i klassen FakeTimeProvider:

  • Ange ett specifikt datum och en viss tid.
  • För fram datum och tid automatiskt med ett angivet belopp när datum och tid läss.
  • Föra fram datum och tid manuellt.

Specialanpassad implementering

Även om FakeTimeProvider bör omfatta de flesta scenarier som kräver förutsägbarhet med tiden, kan du fortfarande tillhandahålla din egen implementering. Skapa en ny klass som härleds från TimeProvider och åsidosätt medlemmar för att styra hur tid som ges. Följande klass innehåller till exempel bara ett enda datum, datumet för månlandningen:

public class MoonLandingTimeProviderPST: TimeProvider
{
    // July 20, 1969, at 20:17:40 UTC
    private readonly DateTimeOffset _specificDateTime = new(1969, 7, 20, 20, 17, 40, TimeZoneInfo.Utc.BaseUtcOffset);

    public override DateTimeOffset GetUtcNow() => _specificDateTime;

    public override TimeZoneInfo LocalTimeZone => TimeZoneInfo.FindSystemTimeZoneById("PST");
}
Public Class MoonLandingTimeProviderPST
    Inherits TimeProvider

    'July 20, 1969, at 20:17:40 UTC
    Private ReadOnly _specificDateTime As New DateTimeOffset(1969, 7, 20, 20, 17, 40, TimeZoneInfo.Utc.BaseUtcOffset)

    Public Overrides Function GetUtcNow() As DateTimeOffset
        Return _specificDateTime
    End Function

    Public Overrides ReadOnly Property LocalTimeZone As TimeZoneInfo
        Get
            Return TimeZoneInfo.FindSystemTimeZoneById("PST")
        End Get
    End Property

End Class

Om kod som använder den här klassen anropar MoonLandingTimeProviderPST.GetUtcNowreturneras datumet för månlandningen i UTC. Om MoonLandingTimeProviderPST.GetLocalNow anropas gäller basklassen MoonLandingTimeProviderPST.LocalTimeZone för GetUtcNow och returnerar månens landningsdatum och tid i PST-tidszonen.

Tänk på följande exempel för att visa hur användbart det är att kontrollera tiden. Anta att du skriver en kalenderapp som skickar en hälsning till användaren när appen öppnas varje dag. Appen säger en speciell hälsning när den aktuella dagen har en händelse associerad med den, till exempel årsdagen av månlandningen.

public static class CalendarHelper
{
    static readonly DateTimeOffset MoonLandingDateTime = new(1969, 7, 20, 20, 17, 40, TimeZoneInfo.Utc.BaseUtcOffset);
    
    public static void SendGreeting(TimeProvider currentTime, string name)
    {
        DateTimeOffset localTime = currentTime.GetLocalNow();

        Console.WriteLine($"Good morning, {name}!");
        Console.WriteLine($"The date is {localTime.Date:d} and the day is {localTime.Date.DayOfWeek}.");

        if (localTime.Date.Month == MoonLandingDateTime.Date.Month
            && localTime.Date.Day == MoonLandingDateTime.Date.Day)
        {
            Console.WriteLine("Did you know that on this day in 1969 humans landed on the Moon?");
        }

        Console.WriteLine($"I hope you enjoy your day!");
    }
}
Public Module CalendarHelper

    ReadOnly MoonLandingDateTime As DateTimeOffset = #7/20/1969 20:17:40#

    Public Sub SendGreeting(currentTime As TimeProvider, name As String)

        Dim localTime As DateTimeOffset = currentTime.GetLocalNow()

        Console.WriteLine($"Good morning, {name}!")
        Console.WriteLine($"The date is {localTime.Date:d} and the day is {localTime.Date.DayOfWeek}.")

        If (localTime.Date.Month = MoonLandingDateTime.Date.Month _
            And localTime.Date.Day = MoonLandingDateTime.Date.Day) Then

            Console.WriteLine("Did you know that on this day in 1969 humans landed on the Moon?")
        End If

        Console.WriteLine($"I hope you enjoy your day!")

    End Sub

End Module

Du kan vara benägen att skriva den tidigare koden med DateTime eller DateTimeOffset för att hämta aktuellt datum och tid i stället för TimeProvider. Med enhetstester är det dock svårt att direkt hantera DateTime eller DateTimeOffset. Du skulle antingen behöva köra testerna på månlandningens dag och månad eller ytterligare abstrahera koden till mindre men testbara enheter.

Den normala driften av din app använder TimeProvider.System för att hämta aktuellt datum och tid:

CalendarHelper.SendGreeting(TimeProvider.System, "Eric Solomon");

/* This example produces output similar to the following:
 *
 * Good morning, Eric Solomon! 
 * The date is 12/5/2024 and the day is Thursday. 
 * I hope you enjoy your day! 
*/
CalendarHelper.SendGreeting(TimeProvider.System, "Eric Solomon")

' This example produces output similar to the following:
'
' Good morning, Eric Solomon! 
' The date is 12/5/2024 and the day is Thursday. 
' I hope you enjoy your day!

Och enhetstester kan skrivas för att testa specifika scenarier, till exempel för att testa årsdagen av månlandningen:

CalendarHelper.SendGreeting(new MoonLandingTimeProviderPST(), "Eric Solomon");

/* This example produces output similar to the following:
 *
 * Good morning, Eric Solomon!
 * The date is 7/20/1969 and the day is Sunday.
 * Did you know that on this day in 1969 humans landed on the Moon?
 * I hope you enjoy your day!
*/
CalendarHelper.SendGreeting(New MoonLandingTimeProviderPST(), "Eric Solomon")

' This example produces output similar to the following:
'
' Good morning, Eric Solomon!
' The date is 7/20/1969 and the day is Sunday.
' Did you know that on this day in 1969 humans landed on the Moon?
' I hope you enjoy your day!

Använd med .NET

Från och med .NET 8 tillhandahålls klassen TimeProvider av körtidsbiblioteket. Äldre versioner av .NET eller bibliotek som riktar sig till .NET Standard 2.0 måste referera till Microsoft.Bcl.TimeProvider NuGet-paketet.

Följande metoder som rör asynkron programmering fungerar med TimeProvider:

Använda med .NET Framework

TimeProvider implementeras av Microsoft.Bcl.TimeProvider NuGet-paketet.

Stöd för att arbeta med TimeProvider i asynkrona programmeringsscenarier har lagts till via följande tilläggsmetoder: