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 tersedia pada kerangka kerja berikut:

Kerangka kerja Catatan
.NET 8+ Disertakan dalam kerangka kerja.
.NET 5 - .NET 7 Disediakan dalam Microsoft.Bcl.TimeProvider paket NuGet.
.NET Framework 4.6.2+ Disediakan dalam Microsoft.Bcl.TimeProvider paket NuGet.
.NET Standar 2.0 Disediakan dalam Microsoft.Bcl.TimeProvider paket NuGet.

Kelas TimeProvider menentukan kemampuan berikut:

Implementasi default

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

Contoh berikut menunjukkan cara menggunakan 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 mengambil waktu yang berlalu dengan menggunakan 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 mencakup sebagian besar skenario yang memerlukan prediksi dengan waktu, Anda masih dapat 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 berlaku MoonLandingTimeProviderPST.LocalTimeZone untuk GetUtcNow dan mengembalikan tanggal dan waktu pendaratan bulan di zona waktu PST.

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, pustaka runtime menyediakan kelas TimeProvider. Versi lama .NET atau pustaka yang menargetkan .NET Standard 2.0 harus mereferensikan Microsoft.Bcl.TimeProvider paket NuGet.

Metode berikut yang terkait dengan pekerjaan pemrograman asinkron dengan TimeProvider:

Gunakan dengan .NET Framework

Paket Microsoft.Bcl.TimeProvider NuGet mengimplementasikan TimeProvider.

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