Bagikan melalui


Apa itu TimeProvider?

System.TimeProvider adalah abstraksi waktu yang menunjukkan suatu titik waktu sebagai tipe DateTimeOffset. Dengan menggunakan TimeProvider, Anda memastikan bahwa kode Anda dapat diuji dan dapat diprediksi. TimeProvider diperkenalkan di .NET 8 dan juga tersedia untuk .NET Framework 4.7+ dan .NET Standard 2.0 sebagai paket NuGet.

Kelas TimeProvider menentukan kemampuan berikut:

Implementasi default

.NET menyediakan implementasi TimeProvider melalui properti TimeProvider.System, dengan karakteristik berikut:

Contoh berikut menunjukkan penggunaan TimeProvider untuk mendapatkan tanggal dan waktu saat ini:

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

Contoh berikut menunjukkan cara mengukur waktu yang berlalu dengan 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

Implementasi FakeTimeProvider

Paket Microsoft.Extensions.TimeProvider.Testing NuGet menyediakan implementasi TimeProvider yang dapat dikontrol yang dirancang untuk pengujian unit.

Daftar berikut ini menjelaskan beberapa kemampuan kelas FakeTimeProvider:

  • Atur tanggal dan waktu tertentu.
  • Secara otomatis memajukan tanggal dan waktu dengan jumlah yang ditentukan setiap kali tanggal dan waktu dibaca.
  • Lanjutkan tanggal dan waktu secara manual.

Implementasi kustom

Meskipun FakeTimeProvider harus mencakup sebagian besar skenario yang membutuhkan kepastian waktu, Anda tetap bisa memberikan implementasi Anda sendiri. Buat kelas baru yang berasal dari TimeProvider dan ambil alih anggota untuk mengontrol bagaimana waktu disediakan. Misalnya, kelas berikut hanya menyediakan satu tanggal, tanggal pendaratan bulan:

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

Jika kode yang menggunakan kelas ini memanggil MoonLandingTimeProviderPST.GetUtcNow, tanggal pendaratan bulan di UTC dikembalikan. Jika MoonLandingTimeProviderPST.GetLocalNow dipanggil, kelas dasar menerapkan MoonLandingTimeProviderPST.LocalTimeZone pada GetUtcNow dan mengembalikan tanggal dan waktu pendaratan bulan dalam zona waktu Pasifik.

Untuk menunjukkan kegunaan waktu kontrol, pertimbangkan contoh berikut. Katakanlah Anda menulis aplikasi kalender yang mengirim salam kepada pengguna saat aplikasi pertama kali dibuka setiap hari. Aplikasi ini mengatakan salam khusus ketika hari ini memiliki peristiwa yang terkait dengannya, seperti peringatan pendaratan bulan.

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

Anda mungkin cenderung menulis kode sebelumnya dengan DateTime atau DateTimeOffset untuk mendapatkan tanggal dan waktu saat ini, alih-alih TimeProvider. Namun dengan pengujian unit, sulit untuk langsung mengatasi DateTime atau DateTimeOffset. Anda harus menjalankan tes pada hari dan bulan pendaratan bulan atau lebih lanjut mengabstraksi kode menjadi unit yang lebih kecil tetapi dapat diuji.

Operasi normal aplikasi Anda menggunakan TimeProvider.System untuk mengambil tanggal dan waktu saat ini:

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!

Dan tes unit dapat ditulis untuk menguji skenario tertentu, seperti menguji perayaan ulang tahun pendaratan bulan.

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!

Gunakan dengan .NET

Dimulai dengan .NET 8, kelas TimeProvider disediakan oleh pustaka runtime. Versi lama .NET atau pustaka yang menargetkan .NET Standard 2.0, harus mereferensikan paket Microsoft.Bcl.TimeProvider NuGet.

Metode berikut yang terkait dengan pekerjaan pemrograman asinkron dengan TimeProvider:

Gunakan dengan .NET Framework

TimeProvider diimplementasikan oleh paket Microsoft.Bcl.TimeProvider NuGet.

Dukungan untuk bekerja dengan TimeProvider dalam skenario pemrograman asinkron ditambahkan melalui metode ekstensi berikut: