Lire en anglais

Partager via


Qu’est-ce que TimeProvider ?

System.TimeProvider est une abstraction du temps qui fournit un point dans le temps en tant que type DateTimeOffset. En utilisant TimeProvider, vous assurez que votre code est testable et prévisible. TimeProvider a été introduit dans .NET 8 et est également disponible pour .NET Framework 4.7+ et .NET Standard 2.0 en tant que package NuGet.

La classe TimeProvider définit les fonctionnalités suivantes :

Implémentation par défaut

.NET fournit une implémentation de TimeProvider via la propriété TimeProvider.System, avec les caractéristiques suivantes :

L’exemple suivant montre comment utiliser TimeProvider pour obtenir la date et l’heure actuelles :

C#
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
*/

L’exemple suivant illustre la capture du temps écoulé avec TimeProvider.GetTimestamp():

C#
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
*/

Implémentation de FakeTimeProvider

Le package NuGet Microsoft.Extensions.TimeProvider.Testing fournit une implémentation TimeProvider contrôlable conçue pour les tests unitaires.

La liste suivante décrit certaines des fonctionnalités de la classe FakeTimeProvider :

  • Définissez une date et une heure spécifiques.
  • Avancez automatiquement la date et l’heure par un montant spécifié chaque fois que la date et l’heure sont lues.
  • Avancez manuellement la date et l’heure.

Implémentation personnalisée

Bien que FakeTimeProvider couvre la plupart des scénarios nécessitant une prévisibilité avec le temps, vous pouvez toujours fournir votre propre implémentation. Créez une nouvelle classe qui dérive de TimeProvider et remplacez les membres pour contrôler la façon dont le temps est fourni. Par exemple, la classe suivante fournit uniquement une date unique, la date de l’atterrissage lunaire :

C#
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");
}

Si le code utilisant cette classe appelle MoonLandingTimeProviderPST.GetUtcNow, la date de l’atterrissage lunaire au format UTC est retournée. Si MoonLandingTimeProviderPST.GetLocalNow est appelée, la classe de base applique MoonLandingTimeProviderPST.LocalTimeZone à GetUtcNow et retourne la date et l’heure d’atterrissage de la lune dans le fuseau horaire PST.

Pour illustrer l’utilité du contrôle du temps, considérez l’exemple suivant. Supposons que vous écrivez une application de calendrier qui envoie un message d’accueil à l’utilisateur lorsque l’application est ouverte chaque jour. L’application indique un message d’accueil spécial lorsque la journée actuelle a un événement associé à celui-ci, tel que l’anniversaire de l’atterrissage lunaire.

C#
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!");
    }
}

Vous pouvez être enclin à écrire le code précédent avec DateTime ou DateTimeOffset pour obtenir la date et l’heure actuelles, au lieu de TimeProvider. Mais avec des tests unitaires, il est difficile de contourner DateTime ou DateTimeOffset directement. Vous devrez soit exécuter les tests le jour et le mois de l’atterrissage lunaire, soit extraire davantage le code en unités plus petites mais testables.

L’opération normale de votre application utilise TimeProvider.System pour récupérer la date et l’heure actuelles :

C#
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! 
*/

Et les tests unitaires peuvent être écrits pour tester des scénarios spécifiques, tels que le test de l’anniversaire de l’atterrissage lunaire :

C#
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!
*/

Utiliser avec .NET

À compter de .NET 8, la classe TimeProvider est fournie par la bibliothèque runtime. Les anciennes versions de .NET ou les bibliothèques ciblant .NET Standard 2.0 doivent faire référence au package NuGet Microsoft.Bcl.TimeProvider.

Les méthodes suivantes liées à la programmation asynchrone fonctionnent avec TimeProvider:

Utiliser avec .NET Framework

TimeProvider est implémenté par le package NuGet Microsoft.Bcl.TimeProvider.

La prise en charge de l’utilisation de TimeProvider dans les scénarios de programmation asynchrone a été ajoutée via les méthodes d’extension suivantes :