다음을 통해 공유


TimeProvider란?

System.TimeProvider 특정 시점을 DateTimeOffset 형식으로 제공하는 시간의 추상화입니다. TimeProvider사용하여 코드가 테스트 가능하고 예측 가능한지 확인합니다. TimeProvider .NET 8에서 도입되었으며 .NET Framework 4.7 이상 및 .NET Standard 2.0에도 NuGet 패키지로 사용할 수 있습니다.

TimeProvider 클래스는 다음 기능을 정의합니다.

기본 구현

.NET은 다음과 같은 특성을 사용하여 TimeProvider 속성을 통해 TimeProvider.System 구현합니다.

다음 예제에서는 TimeProvider 사용하여 현재 날짜 및 시간을 가져오는 방법을 보여 줍니다.

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

다음 예제에서는 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 구현

Microsoft.Extensions.TimeProvider.Testing NuGet 패키지 단위 테스트를 위해 설계된 제어 가능한 TimeProvider 구현을 제공합니다.

다음 목록에서는 FakeTimeProvider 클래스의 일부 기능을 설명합니다.

  • 특정 날짜 및 시간을 설정합니다.
  • 날짜와 시간이 읽힐 때마다 이를 지정된 양만큼 자동으로 진행합니다.
  • 날짜 및 시간을 수동으로 설정하세요.

사용자 지정 구현

FakeTimeProvider 시간이 지남에 따라 예측 가능성이 필요한 대부분의 시나리오를 다루어야 하지만 여전히 고유한 구현을 제공할 수 있습니다. TimeProvider에서 파생된 새 클래스를 만들고, 시간을 어떻게 제공할지 제어할 수 있도록 멤버를 재정의하세요. 예를 들어 다음 클래스는 달 착륙 날짜인 단일 날짜만 제공합니다.

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

이 클래스를 사용하는 코드가 MoonLandingTimeProviderPST.GetUtcNow호출하면 UTC에서 달 착륙 날짜가 반환됩니다. MoonLandingTimeProviderPST.GetLocalNow이(가) 호출되면, 기본 클래스는 MoonLandingTimeProviderPST.LocalTimeZoneGetUtcNow을 적용하고, PST 시간대에서 달 착륙 날짜 및 시간을 반환합니다.

시간 제어의 유용성을 보여 주려면 다음 예제를 참조하세요. 매일 앱이 처음 열릴 때 사용자에게 인사말을 보내는 일정 앱을 작성한다고 가정해 보겠습니다. 앱은 현재 날에 달 착륙 기념일과 같은 이벤트와 관련된 이벤트가 있을 때 특별한 인사말을 말합니다.

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

DateTime대신 DateTimeOffset 또는 TimeProvider 사용하여 이전 코드를 작성하여 현재 날짜와 시간을 가져오는 것이 좋습니다. 그러나 단위 테스트를 사용하면 직접 DateTime 또는 DateTimeOffset 해결하기가 어렵습니다. 달 착륙 날짜와 달에 테스트를 실행하거나 코드를 더 작지만 테스트 가능한 단위로 추상화해야 합니다.

앱의 정상적인 작업은 TimeProvider.System 사용하여 현재 날짜 및 시간을 검색합니다.

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!

그리고 단위 테스트를 작성하여 달 착륙 기념일 테스트와 같은 특정 시나리오를 테스트할 수 있습니다.

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!

.NET과 함께 사용

.NET 8부터 TimeProvider 클래스는 런타임 라이브러리에서 제공됩니다. .NET 또는 .NET Standard 2.0을 대상으로 하는 오래된 버전의 라이브러리는 Microsoft.Bcl.TimeProvider NuGet 패키지참조해야 합니다.

비동기 프로그래밍과 관련된 다음 메서드는 TimeProvider와 함께 작업합니다.

.NET Framework와 함께 사용

TimeProviderMicrosoft.Bcl.TimeProvider NuGet 패키지에 의해 구현됩니다.

비동기 프로그래밍 시나리오에서 TimeProvider 작업에 대한 지원은 다음 확장 메서드를 통해 추가되었습니다.