Skip to content

Commit 726a000

Browse files
adegeoIEvangelist
andauthored
Add TimeProvider overview (#43881)
* Add TimeProvider overview * Minor * Add to toc * minor * Various tweaks * Apply suggestions from code review Co-authored-by: David Pine <[email protected]> * Adjust namespaces * Feedback --------- Co-authored-by: David Pine <[email protected]>
1 parent f746b05 commit 726a000

File tree

13 files changed

+367
-12
lines changed

13 files changed

+367
-12
lines changed

docs/fundamentals/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ items:
445445
href: ../standard/datetime/how-to-use-dateonly-timeonly.md
446446
- name: Perform arithmetic operations
447447
href: ../standard/datetime/performing-arithmetic-operations.md
448+
- name: Use TimeProvider to write predictable code
449+
href: ../standard/datetime/timeprovider-overview.md
448450
- name: "DateTime and DateTimeOffset support in System.Text.Json"
449451
href: ../standard/datetime/system-text-json-support.md
450452
- name: Time zones

docs/standard/datetime/choosing-between-datetime.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Although you could use `DateTime` while ignoring the time component, there are a
8080
For more information about `DateOnly`, see [How to use the DateOnly and TimeOnly structures](how-to-use-dateonly-timeonly.md).
8181

8282
> [!IMPORTANT]
83-
> `DateOnly` isn't available in .NET Framework.
83+
> `DateOnly` isn't available for .NET Framework.
8484
8585
## The TimeSpan structure
8686

@@ -115,7 +115,7 @@ Prior to the `TimeOnly` type being introduced, programmers typically used either
115115
For more information about `TimeOnly`, see [How to use the DateOnly and TimeOnly structures](how-to-use-dateonly-timeonly.md).
116116

117117
> [!IMPORTANT]
118-
> `TimeOnly` isn't available in .NET Framework.
118+
> `TimeOnly` isn't available for .NET Framework.
119119
120120
## The TimeZoneInfo class
121121

docs/standard/datetime/how-to-use-dateonly-timeonly.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: How to use DateOnly and TimeOnly
33
description: Learn about the DateOnly and TimeOnly structures in .NET.
4-
ms.date: 01/11/2023
4+
ms.date: 12/05/2024
55
dev_langs:
66
- "csharp"
77
- "vb"
@@ -22,7 +22,7 @@ The <xref:System.DateOnly> and <xref:System.TimeOnly> structures were introduced
2222
`DateOnly` and `TimeOnly` are types that represent those particular portions of a `DateTime` type.
2323

2424
> [!IMPORTANT]
25-
> <xref:System.DateOnly> and <xref:System.TimeOnly> types aren't available in .NET Framework.
25+
> <xref:System.DateOnly> and <xref:System.TimeOnly> types aren't available for .NET Framework.
2626
2727
## The DateOnly structure
2828

docs/standard/datetime/index.md

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description: "Learn more about: Dates, times, and time zones"
33
title: "Dates, times, and time zones"
4-
ms.date: 12/07/2021
4+
ms.date: 12/05/2024
55
helpviewer_keywords:
66
- "time zone objects [.NET]"
77
- "date and time data [.NET]"
@@ -12,11 +12,9 @@ ms.assetid: 295c16e0-641b-4771-94b3-39c1ffa98c13
1212
---
1313
# Dates, times, and time zones
1414

15-
In addition to the basic <xref:System.DateTime> structure, .NET provides the following classes that support working with time zones:
16-
17-
* <xref:System.TimeZone>
15+
.NET provides types that represent dates, times, and time zones. This article describes those types.
1816

19-
Use this class to work with the system's local time zone and the Coordinated Universal Time (UTC) zone. The functionality of the <xref:System.TimeZone> class is largely superseded by the <xref:System.TimeZoneInfo> class.
17+
In addition to the basic <xref:System.DateTime> structure, .NET provides the following classes that support working with time zones:
2018

2119
* <xref:System.TimeZoneInfo>
2220

@@ -26,16 +24,38 @@ In addition to the basic <xref:System.DateTime> structure, .NET provides the fol
2624

2725
Use this structure to work with dates and times whose offset (or difference) from UTC is known. The <xref:System.DateTimeOffset> structure combines a date and time value with that time's offset from UTC. Because of its relationship to UTC, an individual date and time value unambiguously identifies a single point in time. This makes a <xref:System.DateTimeOffset> value more portable from one computer to another than a <xref:System.DateTime> value.
2826

29-
Starting with .NET 6, the following types are available:
27+
The following classes to support working with time:
3028

31-
* <xref:System.DateOnly>
29+
* <xref:System.TimeSpan>
3230

33-
Use this structure when working with a value that only represents a date. The date represents the entire day, from the start of the day to the end. `DateOnly` has a range of `0001-01-01` through `9999-12-31`. And, this type represents the month, day, and year combination without a specific time. If you previously used a `DateTime` type in your code to represent a date that disregarded the time, use this type in its place. For more information, see [How to use the DateOnly and TimeOnly structures](how-to-use-dateonly-timeonly.md).
31+
Use this structure to represents a time interval, such as an elapsed amount of time or the difference between two dates.
3432

3533
* <xref:System.TimeOnly>
3634

3735
Use this structure to represent a time without a date. The time represents the hours, minutes, and seconds of a non-specific day. `TimeOnly` has a range of `00:00:00.0000000` to `23:59:59.9999999`. This type can be used to replace `DateTime` and `TimeSpan` types in your code when you used those types to represent a time. For more information, see [How to use the DateOnly and TimeOnly structures](how-to-use-dateonly-timeonly.md).
3836

37+
> [!IMPORTANT]
38+
> <xref:System.TimeOnly> isn't available for .NET Framework.
39+
40+
* <xref:System.TimeProvider>
41+
42+
This is a base class that provides an abstraction of time. A common way to check the current time is by using `DateTime.UtcNow` or `DateTimeOffset.UtcNow`. However, these types don't provide any control over what's considered "now." Why would you want to control that? Testability. For example, consider you're writing an event tracking application that provides reminders 1 day before the event. The app's logic is to check the event time every hour, and alert the user once it's 24 hours before the event. As you write your tests for the app, you would provide your own type that wraps `DateTimeOffset.UtcNow` to test this logic, but now .NET provides this abstraction class for you.
43+
44+
For more information, see [What is TimeProvider](timeprovider-overview.md).
45+
46+
The `TimeProvider` type is included in .NET.
47+
48+
For .NET Framework and .NET Standard, `TimeProvider` is provided by the [**Microsoft.Bcl.TimeProvider** NuGet package](https://www.nuget.org/packages/Microsoft.Bcl.TimeProvider/).
49+
50+
The following classes to support working with dates:
51+
52+
* <xref:System.DateOnly>
53+
54+
Use this structure when working with a value that only represents a date. The date represents the entire day, from the start of the day to the end. `DateOnly` has a range of `0001-01-01` through `9999-12-31`. And, this type represents the month, day, and year combination without a specific time. If you previously used a `DateTime` type in your code to represent a date that disregarded the time, use this type in its place. For more information, see [How to use the DateOnly and TimeOnly structures](how-to-use-dateonly-timeonly.md).
55+
56+
> [!IMPORTANT]
57+
> <xref:System.DateOnly> isn't available for .NET Framework.
58+
3959
The next section provides the information that you need to work with time zones and to create time zone-aware applications that can convert dates and times from one time zone to another.
4060

4161
## In this section
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace ExampleProject;
2+
3+
//<CalendarHelper>
4+
public static class CalendarHelper
5+
{
6+
static readonly DateTimeOffset MoonLandingDateTime = new(1969, 7, 20, 20, 17, 40, TimeZoneInfo.Utc.BaseUtcOffset);
7+
8+
public static void SendGreeting(TimeProvider currentTime, string name)
9+
{
10+
DateTimeOffset localTime = currentTime.GetLocalNow();
11+
12+
Console.WriteLine($"Good morning, {name}!");
13+
Console.WriteLine($"The date is {localTime.Date:d} and the day is {localTime.Date.DayOfWeek}.");
14+
15+
if (localTime.Date.Month == MoonLandingDateTime.Date.Month
16+
&& localTime.Date.Day == MoonLandingDateTime.Date.Day)
17+
{
18+
Console.WriteLine("Did you know that on this day in 1969 humans landed on the Moon?");
19+
}
20+
21+
Console.WriteLine($"I hope you enjoy your day!");
22+
}
23+
}
24+
//</CalendarHelper>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace ExampleProject;
2+
3+
//<CustomProvider>
4+
public class MoonLandingTimeProviderPST: TimeProvider
5+
{
6+
// July 20, 1969, at 20:17:40 UTC
7+
private readonly DateTimeOffset _specificDateTime = new(1969, 7, 20, 20, 17, 40, TimeZoneInfo.Utc.BaseUtcOffset);
8+
9+
public override DateTimeOffset GetUtcNow() => _specificDateTime;
10+
11+
public override TimeZoneInfo LocalTimeZone => TimeZoneInfo.FindSystemTimeZoneById("PST");
12+
}
13+
//</CustomProvider>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using ExampleProject;
2+
3+
Console.WriteLine(@"_./-==--======- getlocal -======--==-\._");
4+
5+
//<GetLocal>
6+
Console.WriteLine($"Local: {TimeProvider.System.GetLocalNow()}");
7+
Console.WriteLine($"Utc: {TimeProvider.System.GetUtcNow()}");
8+
9+
/* This example produces output similar to the following:
10+
*
11+
* Local: 12/5/2024 10:41:14 AM -08:00
12+
* Utc: 12/5/2024 6:41:14 PM +00:00
13+
*/
14+
//</GetLocal>
15+
16+
Console.WriteLine(@"_./-==--======- timestamp -======--==-\._");
17+
18+
//<Timestamp>
19+
long stampStart = TimeProvider.System.GetTimestamp();
20+
Console.WriteLine($"Starting timestamp: {stampStart}");
21+
22+
long stampEnd = TimeProvider.System.GetTimestamp();
23+
Console.WriteLine($"Ending timestamp: {stampEnd}");
24+
25+
Console.WriteLine($"Elapsed time: {TimeProvider.System.GetElapsedTime(stampStart, stampEnd)}");
26+
Console.WriteLine($"Nanoseconds: {TimeProvider.System.GetElapsedTime(stampStart, stampEnd).TotalNanoseconds}");
27+
28+
/* This example produces output similar to the following:
29+
*
30+
* Starting timestamp: 55185546133
31+
* Ending timestamp: 55185549929
32+
* Elapsed time: 00:00:00.0003796
33+
* Nanoseconds: 379600
34+
*/
35+
//</Timestamp>
36+
37+
Console.WriteLine(@"_./-==--======- greeting-normal -======--==-\._");
38+
39+
//<GreetingNormal>
40+
CalendarHelper.SendGreeting(TimeProvider.System, "Eric Solomon");
41+
42+
/* This example produces output similar to the following:
43+
*
44+
* Good morning, Eric Solomon!
45+
* The date is 12/5/2024 and the day is Thursday.
46+
* I hope you enjoy your day!
47+
*/
48+
//</GreetingNormal>
49+
50+
Console.WriteLine(@"_./-==--======- greeting-moon -======--==-\._");
51+
52+
//<GreetingMoon>
53+
CalendarHelper.SendGreeting(new MoonLandingTimeProviderPST(), "Eric Solomon");
54+
55+
/* This example produces output similar to the following:
56+
*
57+
* Good morning, Eric Solomon!
58+
* The date is 7/20/1969 and the day is Sunday.
59+
* Did you know that on this day in 1969 humans landed on the Moon?
60+
* I hope you enjoy your day!
61+
*/
62+
//</GreetingMoon>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'<CalendarHelper>
2+
Public Module CalendarHelper
3+
4+
ReadOnly MoonLandingDateTime As DateTimeOffset = #7/20/1969 20:17:40#
5+
6+
Public Sub SendGreeting(currentTime As TimeProvider, name As String)
7+
8+
Dim localTime As DateTimeOffset = currentTime.GetLocalNow()
9+
10+
Console.WriteLine($"Good morning, {name}!")
11+
Console.WriteLine($"The date is {localTime.Date:d} and the day is {localTime.Date.DayOfWeek}.")
12+
13+
If (localTime.Date.Month = MoonLandingDateTime.Date.Month _
14+
And localTime.Date.Day = MoonLandingDateTime.Date.Day) Then
15+
16+
Console.WriteLine("Did you know that on this day in 1969 humans landed on the Moon?")
17+
End If
18+
19+
Console.WriteLine($"I hope you enjoy your day!")
20+
21+
End Sub
22+
23+
End Module
24+
'</CalendarHelper>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'<CustomProvider>
2+
Public Class MoonLandingTimeProviderPST
3+
Inherits TimeProvider
4+
5+
'July 20, 1969, at 20:17:40 UTC
6+
Private ReadOnly _specificDateTime As New DateTimeOffset(1969, 7, 20, 20, 17, 40, TimeZoneInfo.Utc.BaseUtcOffset)
7+
8+
Public Overrides Function GetUtcNow() As DateTimeOffset
9+
Return _specificDateTime
10+
End Function
11+
12+
Public Overrides ReadOnly Property LocalTimeZone As TimeZoneInfo
13+
Get
14+
Return TimeZoneInfo.FindSystemTimeZoneById("PST")
15+
End Get
16+
End Property
17+
18+
End Class
19+
'</CustomProvider>

0 commit comments

Comments
 (0)