Freigeben über


Was ist TimeProvider?

System.TimeProviderist eine Abstraktion der Zeit, die einen Zeitpunkt alsDateTimeOffsetTyp bereitstellt. Mit TimeProviderstellen Sie sicher, dass Ihr Code testbar und vorhersehbar ist. TimeProvider wurde in .NET 8 eingeführt und ist auch für .NET Framework 4.7+ und .NET Standard 2.0 als NuGet-Paket verfügbar.

Die TimeProvider Klasse definiert die folgenden Funktionen:

Standardimplementierung

.NET bietet eine Implementierung vonTimeProviderdurch dieTimeProvider.SystemEigenschaft mit den folgenden Merkmalen:

Im folgenden Beispiel wird die Verwendung von TimeProvider zum Abrufen des aktuellen Datums und der aktuellen Uhrzeit veranschaulicht:

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

Das folgende Beispiel zeigt die Erfassung der verstrichenen Zeit mitTimeProvider.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

FakeTimeProvider-Implementierung

Das Microsoft.Extensions.TimeProvider.Testing NuGet-Paket bietet eine kontrollierbare TimeProviderImplementierung, die für Unit-Tests ausgelegt ist.

In der folgenden Liste werden einige der Funktionen der FakeTimeProvider-Klasse beschrieben:

  • Legen Sie ein bestimmtes Datum und eine bestimmte Uhrzeit fest.
  • Stellt das Datum und die Uhrzeit automatisch um einen bestimmten Betrag vor, wenn das Datum und die Uhrzeit gelesen werden.
  • Stellen Sie das Datum und die Uhrzeit manuell vor.

Benutzerdefinierte Implementierung

Während FakeTimeProvider die meisten Szenarien abdecken sollte, die Vorhersehbarkeit in Bezug auf Zeit erfordern, können Sie dennoch Ihre eigene Implementierung bereitstellen. Erstellen Sie eine neue Klasse, die vonTimeProviderabgeleitet ist, und überschreiben Sie Mitglieder, um zu steuern, wie die Zeit bereitgestellt wird. Die folgende Klasse stellt z. B. nur ein einzelnes Datum, das Datum der Mondlandung bereit:

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

Wenn Code, der diese Klasse verwendet, MoonLandingTimeProviderPST.GetUtcNowaufruft, wird das Datum der Mondlandung in UTC zurückgegeben. Wenn MoonLandingTimeProviderPST.GetLocalNow aufgerufen wird, wendet die Basisklasse MoonLandingTimeProviderPST.LocalTimeZone auf GetUtcNow an und gibt das Mondlandungsdatum und die Uhrzeit in der PST-Zeitzone zurück.

Um die Nützlichkeit der Zeitkontrolle zu veranschaulichen, betrachten Sie das folgende Beispiel. Angenommen, Sie schreiben eine Kalender-App, die dem Benutzer eine Begrüßung sendet, wenn die App jeden Tag zum ersten Mal geöffnet wird. Die App gibt eine besondere Begrüßung aus, wenn dem aktuellen Tag ein Ereignis zugeordnet ist, wie der Jahrestag der Mondlandung.

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

Möglicherweise sind Sie geneigt, den vorherigen Code mit DateTime oder DateTimeOffset zu schreiben, um das aktuelle Datum und die aktuelle Uhrzeit anstelle von TimeProviderabzurufen. Aber mit Unit-Tests ist es schwierig, DateTime oder DateTimeOffset direkt zu umgehen. Sie müssen entweder die Tests am Tag und Monat der Mondlandung ausführen oder den Code weiter in kleinere, aber testbare Einheiten abstrahieren.

Der normale Vorgang Ihrer App verwendet TimeProvider.System, um das aktuelle Datum und die aktuelle Uhrzeit abzurufen:

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!

Und Einheitstests können geschrieben werden, um bestimmte Szenarien zu testen, z. B. den Jahrestag der Mondlandung:

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!

Verwendung mit .NET

Ab .NET 8 wird die TimeProvider Klasse von der Laufzeitbibliothek bereitgestellt. Ältere Versionen von .NET oder Bibliotheken, die auf .NET Standard 2.0 abzielen, müssen auf das NuGet-Paket Microsoft.Bcl.TimeProvider verweisen.

Die folgenden Methoden im Zusammenhang mit der asynchronen Programmierung arbeiten mit TimeProvider:

Verwenden mit .NET Framework

TimeProvider wird durch das NuGet-Paket Microsoft.Bcl.TimeProvider implementiert.

Unterstützung für die Arbeit mit TimeProvider in asynchronen Programmierszenarien wurde durch die folgenden Erweiterungsmethoden hinzugefügt: