Megosztás a következőn keresztül:


Mi az a TimeProvider?

System.TimeProvider az idő absztrakciója, amely DateTimeOffset típusú időpontot biztosít. A TimeProviderhasználatával meggyőződhet arról, hogy a kód tesztelhető és kiszámítható. A TimeProvider a .NET 8-ban lett bevezetve, és a .NET-keretrendszer 4.7+ és .NET Standard 2.0-hoz is elérhető NuGet-csomagként.

A TimeProvider osztály a következő képességeket határozza meg:

Alapértelmezett implementáció

A .NET a TimeProvider.System tulajdonságon keresztül biztosítja a TimeProvider implementálását a következő jellemzőkkel:

Az alábbi példa bemutatja, hogy a TimeProvider használatával lekérheti az aktuális dátumot és időpontot:

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

Az alábbi példa az eltelt idő rögzítését mutatja be 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

FakeTimeProvider implementáció

A Microsoft.Extensions.TimeProvider.Testing NuGet-csomag az egységteszteléshez tervezett, szabályozható TimeProvider implementációt biztosít.

Az alábbi lista az FakeTimeProvider osztály néhány funkcióját ismerteti:

  • Adjon meg egy adott dátumot és időpontot.
  • A dátumot és időt automatikusan előrelépteti egy megadott összeggel, amikor a dátum és az idő beolvasása megtörténik.
  • Állítsa be manuálisan a dátumot és az időt.

Egyéni megvalósítás

Bár a FakeTimeProvider a legtöbb olyan forgatókönyvet lefedi, amely időbeli kiszámíthatóságot igényel, továbbra is lehetősége van saját implementáció biztosítására. Hozzon létre egy új osztályt, amely a TimeProvider osztályból származik, és határozza meg újra a metódusokat, hogy meghatározza az idő kezelését. A következő osztály például csak egyetlen dátumot, a holdra szállás dátumát adja meg:

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

Ha az osztályt használó kód meghívja MoonLandingTimeProviderPST.GetUtcNow, a holdra szállás dátuma (UTC) lesz visszaadva. Ha a MoonLandingTimeProviderPST.GetLocalNow meghívásra kerül, az alaposztály alkalmazza a MoonLandingTimeProviderPST.LocalTimeZone-t a GetUtcNow-re, és visszaadja a holdra szállás dátumát és időpontját a PST időzóna szerint.

Az idő szabályozásának hasznosságát az alábbi példában szemlélteti. Tegyük fel, hogy egy olyan naptáralkalmazást ír, amely minden nap, amikor először megnyitják, köszöntést küld a felhasználónak. Az alkalmazás különleges üdvözlést mond, amikor az aktuális naphoz tartozik egy esemény, például a holdra szállás évfordulója.

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

Előfordulhat, hogy az előző kódot DateTime vagy DateTimeOffset megírásával szeretné lekérni az aktuális dátumot és időt TimeProviderhelyett. Az egységteszteléssel azonban nehéz megkerülni közvetlenül a(z) DateTime vagy DateTimeOffset elemeket. Le kell futtatnia a teszteket a holdra szállás napján és hónapján, vagy további kivonatolnia kell a kódot kisebb, de tesztelhető egységekre.

Az alkalmazás normál működése TimeProvider.System használatával kéri le az aktuális dátumot és időpontot:

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!

Az egységtesztek megírhatók konkrét forgatókönyvek tesztelésére, például a holdra szállás évfordulójának tesztelésére:

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!

Használat a .NET-tel

A .NET 8-tól kezdve a TimeProvider osztályt a futtatókörnyezeti kódtár biztosítja. A .NET régebbi verzióinak vagy a .NET Standard 2.0-t célzó kódtáraknak a Microsoft.Bcl.TimeProvider NuGet-csomagrakell hivatkozniuk.

Az aszinkron programozáshoz kapcsolódó alábbi módszerek a TimeProvider-tal dolgoznak:

Használat a .NET-keretrendszerrel

a Microsoft.Bcl.TimeProvider NuGet-csomagvalósítja meg.

A TimeProvider aszinkron programozási forgatókönyvekben való használatának támogatása a következő bővítménymetelyekkel lett hozzáadva: