diff --git a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/DateOnlyAndTimeOnlyInCSharpExample.csproj b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/DateOnlyAndTimeOnlyInCSharpExample.csproj
index 74abf5c976..dfb40caafc 100644
--- a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/DateOnlyAndTimeOnlyInCSharpExample.csproj
+++ b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/DateOnlyAndTimeOnlyInCSharpExample.csproj
@@ -2,7 +2,7 @@
Exe
- net6.0
+ net10.0
enable
enable
diff --git a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/Program.cs b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/Program.cs
index 7154c7263f..0f108c3ed0 100644
--- a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/Program.cs
+++ b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/DateOnlyAndTimeOnlyInCSharpExample/Program.cs
@@ -1,12 +1,19 @@
-namespace DateOnlyAndTimeOnlyInCSharpExample;
+using System.Globalization;
+
+namespace DateOnlyAndTimeOnlyInCSharpExample;
public class Program
{
public static void Main()
{
+ // The printed output below is culture-dependent, so we state the culture
+ // instead of letting the host machine decide what the samples look like.
+ CultureInfo.CurrentCulture = new CultureInfo("en-US");
+
DemonstrateDateOnly();
DemonstrateTimeOnly();
DemonstrateFromDateTime();
+ DemonstrateConversions();
DemonstrateBasicOperators();
}
@@ -62,6 +69,54 @@ public static void DemonstrateFromDateTime()
Console.WriteLine(timeOnly);
}
+ public static void DemonstrateConversions()
+ {
+ var dateOnly = new DateOnly(2022, 1, 1);
+ var timeOnly = new TimeOnly(11, 30);
+
+ // DateOnly back to DateTime, in all three shapes.
+ var combined = dateOnly.ToDateTime(timeOnly);
+ var midnight = dateOnly.ToDateTime(TimeOnly.MinValue);
+ var utc = dateOnly.ToDateTime(timeOnly, DateTimeKind.Utc);
+
+ Console.WriteLine($"{combined:O} Kind={combined.Kind}");
+ Console.WriteLine($"{midnight:O} Kind={midnight.Kind}");
+ Console.WriteLine($"{utc:O} Kind={utc.Kind}");
+
+ // Neither type has a Now or a Today property.
+ var today = DateOnly.FromDateTime(DateTime.Now);
+ var timeOfDay = TimeOnly.FromDateTime(DateTime.Now);
+
+ Console.WriteLine(today);
+ Console.WriteLine(timeOfDay);
+
+ // TimeSpan in both directions.
+ var fromTimeSpan = TimeOnly.FromTimeSpan(TimeSpan.FromHours(11.5));
+ var sinceMidnight = timeOnly.ToTimeSpan();
+
+ Console.WriteLine(fromTimeSpan);
+ Console.WriteLine(sinceMidnight);
+
+ // The underlying day count.
+ var dayNumber = dateOnly.DayNumber;
+ var fromDayNumber = DateOnly.FromDayNumber(dayNumber);
+
+ Console.WriteLine(dayNumber);
+ Console.WriteLine(fromDayNumber);
+
+ // Parsing a string in a known, fixed format.
+ var parsed = DateOnly.ParseExact("2022-01-01", "yyyy-MM-dd");
+
+ Console.WriteLine(parsed);
+
+ // AddHours wraps past midnight; the second overload reports the day boundary.
+ var elevenPM = new TimeOnly(23, 0);
+ var wrapped = elevenPM.AddHours(2);
+ var wrappedWithCount = elevenPM.AddHours(2, out var excessDays);
+
+ Console.WriteLine($"{wrapped} / {wrappedWithCount} excessDays={excessDays}");
+ }
+
public static void DemonstrateBasicOperators()
{
var firstOfJan = new DateOnly(2022, 1, 1);
diff --git a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/DateOnlyTests.cs b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/DateOnlyTests.cs
index fecbd41c64..33dca3836a 100644
--- a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/DateOnlyTests.cs
+++ b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/DateOnlyTests.cs
@@ -112,5 +112,92 @@ public void CanUseGreaterThanOperator()
// Assert.
Assert.True(isAfter);
}
+ [Fact]
+ public void CanParseExactWithAKnownFormat()
+ {
+ // Arrange.
+ var text = "2022-01-01";
+
+ // Act.
+ var date = DateOnly.ParseExact(text, "yyyy-MM-dd");
+
+ // Assert.
+ Assert.Equal(new DateOnly(2022, 1, 1), date);
+ }
+
+ [Fact]
+ public void CanConvertToDateTimeWithATimeOnly()
+ {
+ // Arrange.
+ var dateOnly = new DateOnly(2022, 1, 1);
+ var timeOnly = new TimeOnly(11, 30);
+
+ // Act.
+ var combined = dateOnly.ToDateTime(timeOnly);
+
+ // Assert.
+ Assert.Equal(new DateTime(2022, 1, 1, 11, 30, 0), combined);
+ Assert.Equal(DateTimeKind.Unspecified, combined.Kind);
+ }
+
+ [Fact]
+ public void CanConvertToDateTimeAtMidnight()
+ {
+ // Arrange.
+ var dateOnly = new DateOnly(2022, 1, 1);
+
+ // Act.
+ var midnight = dateOnly.ToDateTime(TimeOnly.MinValue);
+
+ // Assert.
+ Assert.Equal(new DateTime(2022, 1, 1, 0, 0, 0), midnight);
+ Assert.Equal(DateTimeKind.Unspecified, midnight.Kind);
+ }
+
+ [Fact]
+ public void CanConvertToDateTimeWithAKnownKind()
+ {
+ // Arrange.
+ var dateOnly = new DateOnly(2022, 1, 1);
+ var timeOnly = new TimeOnly(11, 30);
+
+ // Act.
+ var utc = dateOnly.ToDateTime(timeOnly, DateTimeKind.Utc);
+
+ // Assert.
+ Assert.Equal(DateTimeKind.Utc, utc.Kind);
+ Assert.Equal(new DateTime(2022, 1, 1, 11, 30, 0, DateTimeKind.Utc), utc);
+ }
+
+ [Fact]
+ public void CanGetTodaysDateFromDateTimeNow()
+ {
+ // Arrange.
+ var now = DateTime.Now;
+
+ // Act.
+ var today = DateOnly.FromDateTime(now);
+
+ // Assert. CI runs at an arbitrary instant, so we assert consistency, not a value.
+ Assert.Equal(now.Year, today.Year);
+ Assert.Equal(now.Month, today.Month);
+ Assert.Equal(now.Day, today.Day);
+ }
+
+ [Fact]
+ public void CanRoundTripThroughDayNumber()
+ {
+ // Arrange.
+ var dateOnly = new DateOnly(2022, 1, 1);
+
+ // Act.
+ var dayNumber = dateOnly.DayNumber;
+ var roundTripped = DateOnly.FromDayNumber(dayNumber);
+
+ // Assert.
+ Assert.Equal(dateOnly, roundTripped);
+ Assert.Equal(1, dateOnly.DayNumber - new DateOnly(2021, 12, 31).DayNumber);
+ }
+
}
}
\ No newline at end of file
diff --git a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/Tests.csproj b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/Tests.csproj
index 9f77f5f615..5ea8ec1057 100644
--- a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/Tests.csproj
+++ b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/Tests.csproj
@@ -1,20 +1,20 @@
- net6.0
+ net10.0
enable
false
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/TimeOnlyTests.cs b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/TimeOnlyTests.cs
index 4d8d3edc46..ba3fb00a18 100644
--- a/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/TimeOnlyTests.cs
+++ b/dotnet-datetime/DateOnlyAndTimeOnlyInCSharp/Tests/TimeOnlyTests.cs
@@ -97,5 +97,67 @@ public void CanUseGreaterThanOperator()
// Assert.
Assert.True(isAfter);
}
+ [Fact]
+ public void CanConvertToAndFromTimeSpan()
+ {
+ // Arrange.
+ var timeOnly = new TimeOnly(11, 30);
+
+ // Act.
+ var sinceMidnight = timeOnly.ToTimeSpan();
+ var roundTripped = TimeOnly.FromTimeSpan(sinceMidnight);
+
+ // Assert.
+ Assert.Equal(TimeSpan.FromHours(11.5), sinceMidnight);
+ Assert.Equal(timeOnly, roundTripped);
+ }
+
+ [Fact]
+ public void CanGetTheCurrentTimeOfDayFromDateTimeNow()
+ {
+ // Arrange.
+ var now = DateTime.Now;
+
+ // Act.
+ var timeOfDay = TimeOnly.FromDateTime(now);
+
+ // Assert. CI runs at an arbitrary instant, so we assert consistency, not a value.
+ Assert.Equal(now.Hour, timeOfDay.Hour);
+ Assert.Equal(now.Minute, timeOfDay.Minute);
+ Assert.Equal(now.TimeOfDay.Ticks, timeOfDay.Ticks);
+ }
+
+ [Fact]
+ public void AddHoursWrapsPastMidnightAndCanReportTheExcessDays()
+ {
+ // Arrange.
+ var elevenPM = new TimeOnly(23, 0);
+
+ // Act.
+ var wrapped = elevenPM.AddHours(2);
+ var wrappedWithCount = elevenPM.AddHours(2, out var excessDays);
+
+ // Assert.
+ Assert.Equal(new TimeOnly(1, 0), wrapped);
+ Assert.Equal(new TimeOnly(1, 0), wrappedWithCount);
+ Assert.Equal(1, excessDays);
+ }
+
+ [Fact]
+ public void SubtractingTwoValuesIsAlwaysPositive()
+ {
+ // Arrange.
+ var elevenPM = new TimeOnly(23, 0);
+ var oneAM = new TimeOnly(1, 0);
+
+ // Act.
+ var forwards = oneAM - elevenPM;
+ var backwards = elevenPM - oneAM;
+
+ // Assert.
+ Assert.Equal(TimeSpan.FromHours(2), forwards);
+ Assert.Equal(TimeSpan.FromHours(22), backwards);
+ }
+
}
}
\ No newline at end of file