Jak używać struktur DateOnly i TimeOnly

Struktury DateOnly i TimeOnly zostały wprowadzone z platformą .NET 6 i reprezentują odpowiednio określoną datę lub godzinę dnia. Przed platformą .NET 6 i zawsze w programie .NET Framework deweloperzy używali DateTime typu (lub innej alternatywy) do reprezentowania jednego z następujących elementów:

  • Cała data i godzina.
  • Data, lekceważąc godzinę.
  • Godzina, pomijając datę.

DateOnly i TimeOnly są typami reprezentującymi DateTime te konkretne części typu.

Ważne

DateOnly typy i TimeOnly nie są dostępne w programie .NET Framework.

Struktura DateOnly

Struktura DateOnly reprezentuje określoną datę bez godziny. Ponieważ nie ma składnika czasu, reprezentuje datę od początku dnia do końca dnia. Ta struktura jest idealna do przechowywania określonych dat, takich jak data urodzenia, data rocznicy lub daty związane z firmą.

Chociaż można użyć DateTime podczas ignorowania składnika czasu, istnieje kilka korzyści związanych z używaniem funkcji DateOnly over DateTime:

  • Struktura DateTime może zostać przerzuciona do poprzedniego lub następnego dnia, jeśli zostanie przesunięta przez strefę czasową. DateOnly nie można zrównoważyć przez strefę czasową i zawsze reprezentuje datę ustawioną.

  • Serializowanie DateTime struktury obejmuje składnik czasu, który może zaciemniać intencję danych. DateOnly Ponadto serializuje mniej danych.

  • Gdy kod wchodzi w interakcję z bazą danych, taką jak program SQL Server, wszystkie daty są zwykle przechowywane jako date typ danych, który nie zawiera czasu. DateOnly pasuje do typu bazy danych lepiej.

DateOnly ma zakres od 0001-01-01 do 9999-12-31, podobnie jak DateTime. Można określić określony kalendarz w konstruktorze DateOnly . DateOnly Jednak obiekt zawsze reprezentuje datę w kalendarzu proleptycznym gregoriańskim, niezależnie od tego, który kalendarz został użyty do jego skonstruowania. Można na przykład skompilować datę z kalendarza hebrajskiego, ale data jest konwertowana na gregoriański:

var hebrewCalendar = new System.Globalization.HebrewCalendar();
var theDate = new DateOnly(5776, 2, 8, hebrewCalendar); // 8 Cheshvan 5776

Console.WriteLine(theDate);

/* This example produces the following output:
 *
 * 10/21/2015
*/
Dim hebrewCalendar = New System.Globalization.HebrewCalendar()
Dim theDate = New DateOnly(5776, 2, 8, hebrewCalendar) ' 8 Cheshvan 5776

Console.WriteLine(theDate)

' This example produces the following output
'
' 10/21/2015

Przykłady dateOnly

Skorzystaj z poniższych przykładów, aby dowiedzieć się więcej o DateOnly:

Konwertowanie daty/godziny na wartość DateOnly

Użyj metody statycznej DateOnly.FromDateTime , aby utworzyć DateOnly typ na podstawie DateTime typu, jak pokazano w poniższym kodzie:

var today = DateOnly.FromDateTime(DateTime.Now);
Console.WriteLine($"Today is {today}");

/* This example produces output similar to the following:
 * 
 * Today is 12/28/2022
*/
Dim today = DateOnly.FromDateTime(DateTime.Now)
Console.WriteLine($"Today is {today}")

' This example produces output similar to the following
' 
' Today is 12/28/2022

Dodawanie lub odejmowanie dni, miesięcy, lat

Istnieją trzy metody służące do dostosowywania DateOnly struktury: AddDays, AddMonthsi AddYears. Każda metoda przyjmuje parametr liczby całkowitej i zwiększa datę o tę miarę. Jeśli zostanie podana liczba ujemna, data zostanie zmniejszona przez ten pomiar. Metody zwracają nowe wystąpienie DateOnlyklasy , ponieważ struktura jest niezmienna.

var theDate = new DateOnly(2015, 10, 21);

var nextDay = theDate.AddDays(1);
var previousDay = theDate.AddDays(-1);
var decadeLater = theDate.AddYears(10);
var lastMonth = theDate.AddMonths(-1);

Console.WriteLine($"Date: {theDate}");
Console.WriteLine($" Next day: {nextDay}");
Console.WriteLine($" Previous day: {previousDay}");
Console.WriteLine($" Decade later: {decadeLater}");
Console.WriteLine($" Last month: {lastMonth}");

/* This example produces the following output:
 * 
 * Date: 10/21/2015
 *  Next day: 10/22/2015
 *  Previous day: 10/20/2015
 *  Decade later: 10/21/2025
 *  Last month: 9/21/2015
*/
Dim theDate = New DateOnly(2015, 10, 21)

Dim nextDay = theDate.AddDays(1)
Dim previousDay = theDate.AddDays(-1)
Dim decadeLater = theDate.AddYears(10)
Dim lastMonth = theDate.AddMonths(-1)

Console.WriteLine($"Date: {theDate}")
Console.WriteLine($" Next day: {nextDay}")
Console.WriteLine($" Previous day: {previousDay}")
Console.WriteLine($" Decade later: {decadeLater}")
Console.WriteLine($" Last month: {lastMonth}")

' This example produces the following output
' 
' Date: 10/21/2015
'  Next day: 10/22/2015
'  Previous day: 10/20/2015
'  Decade later: 10/21/2025
'  Last month: 9/21/2015

Analizowanie i formatowanie datyonly

DateOnly można przeanalizować z ciągu, podobnie jak struktura DateTime . Wszystkie standardowe tokeny analizowania dat na platformie .NET działają z usługą DateOnly. Podczas konwertowania DateOnly typu na ciąg można również użyć standardowych wzorców formatowania na podstawie daty platformy .NET. Aby uzyskać więcej informacji na temat formatowania ciągów, zobacz Standardowe ciągi formatu daty i godziny.

var theDate = DateOnly.ParseExact("21 Oct 2015", "dd MMM yyyy", CultureInfo.InvariantCulture);  // Custom format
var theDate2 = DateOnly.Parse("October 21, 2015", CultureInfo.InvariantCulture);

Console.WriteLine(theDate.ToString("m", CultureInfo.InvariantCulture));     // Month day pattern
Console.WriteLine(theDate2.ToString("o", CultureInfo.InvariantCulture));    // ISO 8601 format
Console.WriteLine(theDate2.ToLongDateString());

/* This example produces the following output:
 * 
 * October 21
 * 2015-10-21
 * Wednesday, October 21, 2015
*/
Dim theDate = DateOnly.ParseExact("21 Oct 2015", "dd MMM yyyy", CultureInfo.InvariantCulture) ' Custom format
Dim theDate2 = DateOnly.Parse("October 21, 2015", CultureInfo.InvariantCulture)

Console.WriteLine(theDate.ToString("m", CultureInfo.InvariantCulture))     ' Month day pattern
Console.WriteLine(theDate2.ToString("o", CultureInfo.InvariantCulture))    ' ISO 8601 format
Console.WriteLine(theDate2.ToLongDateString())

' This example produces the following output
' 
' October 21
' 2015-10-21
' Wednesday, October 21, 2015

Porównywanie datyonly

DateOnly można porównać z innymi wystąpieniami. Możesz na przykład sprawdzić, czy data jest wcześniejsza lub późniejsza, albo czy data dzisiaj jest zgodna z określoną datą.

var theDate = DateOnly.ParseExact("21 Oct 2015", "dd MMM yyyy", CultureInfo.InvariantCulture);  // Custom format
var theDate2 = DateOnly.Parse("October 21, 2015", CultureInfo.InvariantCulture);
var dateLater = theDate.AddMonths(6);
var dateBefore = theDate.AddDays(-10);

Console.WriteLine($"Consider {theDate}...");
Console.WriteLine($" Is '{nameof(theDate2)}' equal? {theDate == theDate2}");
Console.WriteLine($" Is {dateLater} after? {dateLater > theDate} ");
Console.WriteLine($" Is {dateLater} before? {dateLater < theDate} ");
Console.WriteLine($" Is {dateBefore} after? {dateBefore > theDate} ");
Console.WriteLine($" Is {dateBefore} before? {dateBefore < theDate} ");

/* This example produces the following output:
 * 
 * Consider 10/21/2015
 *  Is 'theDate2' equal? True
 *  Is 4/21/2016 after? True
 *  Is 4/21/2016 before? False
 *  Is 10/11/2015 after? False
 *  Is 10/11/2015 before? True
*/
Dim theDate = DateOnly.ParseExact("21 Oct 2015", "dd MMM yyyy", CultureInfo.InvariantCulture) ' Custom format
Dim theDate2 = DateOnly.Parse("October 21, 2015", CultureInfo.InvariantCulture)
Dim dateLater = theDate.AddMonths(6)
Dim dateBefore = theDate.AddDays(-10)

Console.WriteLine($"Consider {theDate}...")
Console.WriteLine($" Is '{NameOf(theDate2)}' equal? {theDate = theDate2}")
Console.WriteLine($" Is {dateLater} after? {dateLater > theDate} ")
Console.WriteLine($" Is {dateLater} before? {dateLater < theDate} ")
Console.WriteLine($" Is {dateBefore} after? {dateBefore > theDate} ")
Console.WriteLine($" Is {dateBefore} before? {dateBefore < theDate} ")

' This example produces the following output
' 
' Consider 10/21/2015
'  Is 'theDate2' equal? True
'  Is 4/21/2016 after? True
'  Is 4/21/2016 before? False
'  Is 10/11/2015 after? False
'  Is 10/11/2015 before? True

Struktura TimeOnly

Struktura TimeOnly reprezentuje wartość godziny dnia, taką jak dzienny zegar alarmowy lub godzina jedzenia lunchu każdego dnia. TimeOnlyjest ograniczony do zakresu 00:00:00.0000000 - 23:59:59.99999999, określonej godziny dnia.

Przed wprowadzeniem TimeOnly typu programiści zazwyczaj używali DateTime typu lub TimeSpan typu do reprezentowania określonego czasu. Jednak użycie tych struktur do symulowania godziny bez daty może spowodować pewne problemy, które TimeOnly rozwiązuje:

  • TimeSpan reprezentuje czas, który upłynął, na przykład czas mierzony za pomocą stopera. Górny zakres wynosi ponad 29 000 lat, a jego wartość może być ujemna, aby wskazać przechodzenie do tyłu w czasie. Wartość ujemna TimeSpan nie wskazuje określonej godziny dnia.

  • Jeśli TimeSpan jest używana jako pora dnia, istnieje ryzyko, że może to być manipulowane wartością poza 24-godzinnym dniem. TimeOnly nie ma tego ryzyka. Jeśli na przykład zmiana pracy pracownika rozpoczyna się o godzinie 18:00 i trwa 8 godzin, dodanie 8 godzin do struktury przerzuca się do TimeOnly 2:00

  • Użycie DateTime przez godzinę dnia wymaga, aby dowolna data została skojarzona z godziną, a następnie zlekceważona. Powszechną praktyką jest wybranie DateTime.MinValue (0001-01-01) jako daty, jednak jeśli godziny są odejmowane od DateTime wartości, OutOfRange może wystąpić wyjątek. TimeOnly nie ma tego problemu, ponieważ czas jest przerzucany do przodu i do tyłu wokół 24-godzinnego przedziału czasu.

  • Serializowanie DateTime struktury obejmuje składnik daty, który może zaciemniać intencję danych. TimeOnly Ponadto serializuje mniej danych.

Przykłady timeonly

Skorzystaj z poniższych przykładów, aby dowiedzieć się więcej o TimeOnly:

Konwertowanie daty/godziny na timeOnly

Użyj metody statycznej TimeOnly.FromDateTime , aby utworzyć TimeOnly typ na podstawie DateTime typu, jak pokazano w poniższym kodzie:

var now = TimeOnly.FromDateTime(DateTime.Now);
Console.WriteLine($"It is {now} right now");

/* This example produces output similar to the following:
 * 
 * It is 2:01 PM right now
*/
Dim now = TimeOnly.FromDateTime(DateTime.Now)
Console.WriteLine($"It is {now} right now")

' This example produces output similar to the following
' 
' It is 2:01 PM right now

Dodawanie lub odejmowanie czasu

Istnieją trzy metody służące do dostosowywania TimeOnly struktury: AddHours, AddMinutesi Add. Zarówno AddHours , jak i AddMinutes weź parametr liczby całkowitej i odpowiednio dostosuj wartość. Możesz użyć wartości ujemnej, aby odjąć i wartość dodatnią do dodania. Metody zwracają nowe wystąpienie TimeOnly obiektu , ponieważ struktura jest niezmienna. Metoda Add przyjmuje TimeSpan parametr i dodaje lub odejmuje wartość z TimeOnly wartości.

Ponieważ TimeOnly reprezentuje tylko okres 24-godzinny, jest on przerzucany do przodu lub do tyłu odpowiednio podczas dodawania wartości dostarczonych do tych trzech metod. Jeśli na przykład używasz wartości 01:30:00 do reprezentowania 1:30, dodaj -4 godziny od tego okresu, powoduje to wycofanie się do 21:30:00wartości , czyli 19:30. Istnieją przeciążenia metod , AddHoursAddMinutesiAdd, które przechwytują liczbę dni przerzucanych.

var theTime = new TimeOnly(7, 23, 11);

var hourLater = theTime.AddHours(1);
var minutesBefore = theTime.AddMinutes(-12);
var secondsAfter = theTime.Add(TimeSpan.FromSeconds(10));
var daysLater = theTime.Add(new TimeSpan(hours: 21, minutes: 200, seconds: 83), out int wrappedDays);
var daysBehind = theTime.AddHours(-222, out int wrappedDaysFromHours);

Console.WriteLine($"Time: {theTime}");
Console.WriteLine($" Hours later: {hourLater}");
Console.WriteLine($" Minutes before: {minutesBefore}");
Console.WriteLine($" Seconds after: {secondsAfter}");
Console.WriteLine($" {daysLater} is the time, which is {wrappedDays} days later");
Console.WriteLine($" {daysBehind} is the time, which is {wrappedDaysFromHours} days prior");

/* This example produces the following output:
 * 
 * Time: 7:23 AM
 *  Hours later: 8:23 AM
 *  Minutes before: 7:11 AM
 *  Seconds after: 7:23 AM
 *  7:44 AM is the time, which is 1 days later 
 *  1:23 AM is the time, which is -9 days prior
*/
Dim wrappedDays As Integer
Dim wrappedDaysFromHours As Integer

Dim theTime = New TimeOnly(7, 23, 11)

Dim hourLater = theTime.AddHours(1)
Dim minutesBefore = theTime.AddMinutes(-12)
Dim secondsAfter = theTime.Add(TimeSpan.FromSeconds(10))
Dim daysLater = theTime.Add(New TimeSpan(hours:=21, minutes:=200, seconds:=83), wrappedDays)
Dim daysBehind = theTime.AddHours(-222, wrappedDaysFromHours)

Console.WriteLine($"Time: {theTime}")
Console.WriteLine($" Hours later: {hourLater}")
Console.WriteLine($" Minutes before: {minutesBefore}")
Console.WriteLine($" Seconds after: {secondsAfter}")
Console.WriteLine($" {daysLater} is the time, which is {wrappedDays} days later")
Console.WriteLine($" {daysBehind} is the time, which is {wrappedDaysFromHours} days prior")

' This example produces the following output
' 
' Time: 7:23 AM
'  Hours later: 8:23 AM
'  Minutes before: 7:11 AM
'  Seconds after: 7:23 AM
'  7:44 AM is the time, which is 1 days later 
'  1:23 AM is the time, which is -9 days prior

Analizowanie i formatowanie timeonly

TimeOnly można przeanalizować z ciągu, podobnie jak struktura DateTime . Wszystkie standardowe tokeny analizy oparte na czasie platformy .NET działają z usługą TimeOnly. Podczas konwertowania TimeOnly typu na ciąg można również użyć standardowych wzorców formatowania na podstawie daty platformy .NET. Aby uzyskać więcej informacji na temat formatowania ciągów, zobacz Standardowe ciągi formatu daty i godziny.

var theTime = TimeOnly.ParseExact("5:00 pm", "h:mm tt", CultureInfo.InvariantCulture);  // Custom format
var theTime2 = TimeOnly.Parse("17:30:25", CultureInfo.InvariantCulture);

Console.WriteLine(theTime.ToString("o", CultureInfo.InvariantCulture));     // Round-trip pattern.
Console.WriteLine(theTime2.ToString("t", CultureInfo.InvariantCulture));    // Long time format
Console.WriteLine(theTime2.ToLongTimeString());

/* This example produces the following output:
 * 
 * 17:00:00.0000000
 * 17:30
 * 5:30:25 PM
*/
Dim theTime = TimeOnly.ParseExact("5:00 pm", "h:mm tt", CultureInfo.InvariantCulture) ' Custom format
Dim theTime2 = TimeOnly.Parse("17:30:25", CultureInfo.InvariantCulture)

Console.WriteLine(theTime.ToString("o", CultureInfo.InvariantCulture))     ' Round-trip pattern.
Console.WriteLine(theTime2.ToString("t", CultureInfo.InvariantCulture))    ' Long time format
Console.WriteLine(theTime2.ToLongTimeString())

' This example produces the following output
' 
' 17:00:00.0000000
' 17:30
' 5:30:25 PM

Serializowanie typów DateOnly i TimeOnly

Program .NET 7+ System.Text.Json obsługuje serializowanie i deserializacji DateOnly oraz TimeOnly typów. Rozważmy następujący obiekt:

sealed file record Appointment(
    Guid Id,
    string Description,
    DateOnly Date,
    TimeOnly StartTime,
    TimeOnly EndTime);
Public NotInheritable Class Appointment
    Public Property Id As Guid
    Public Property Description As String
    Public Property DateValue As DateOnly?
    Public Property StartTime As TimeOnly?
    Public Property EndTime As TimeOnly?
End Class

Poniższy przykład serializuje Appointment obiekt, wyświetla wynikowy kod JSON, a następnie deserializuje go z powrotem do nowego wystąpienia Appointment typu. Na koniec oryginalne i nowo zdeserializowane wystąpienia są porównywane pod kątem równości, a wyniki są zapisywane w konsoli:

Appointment originalAppointment = new(
    Id: Guid.NewGuid(),
    Description: "Take dog to veterinarian.",
    Date: new DateOnly(2002, 1, 13),
    StartTime: new TimeOnly(5,15),
    EndTime: new TimeOnly(5, 45));
string serialized = JsonSerializer.Serialize(originalAppointment);

Console.WriteLine($"Resulting JSON: {serialized}");

Appointment deserializedAppointment =
    JsonSerializer.Deserialize<Appointment>(serialized)!;

bool valuesAreTheSame = originalAppointment == deserializedAppointment;
Console.WriteLine($"""
    Original record has the same values as the deserialized record: {valuesAreTheSame}
    """);
        Dim originalAppointment As New Appointment With {
            .Id = Guid.NewGuid(),
            .Description = "Take dog to veterinarian.",
            .DateValue = New DateOnly(2002, 1, 13),
            .StartTime = New TimeOnly(5, 3, 1),
            .EndTime = New TimeOnly(5, 3, 1)
}
        Dim serialized As String = JsonSerializer.Serialize(originalAppointment)

        Console.WriteLine($"Resulting JSON: {serialized}")

        Dim deserializedAppointment As Appointment =
            JsonSerializer.Deserialize(Of Appointment)(serialized)

        Dim valuesAreTheSame As Boolean =
            (originalAppointment.DateValue = deserializedAppointment.DateValue AndAlso
            originalAppointment.StartTime = deserializedAppointment.StartTime AndAlso
            originalAppointment.EndTime = deserializedAppointment.EndTime AndAlso
            originalAppointment.Id = deserializedAppointment.Id AndAlso
            originalAppointment.Description = deserializedAppointment.Description)

        Console.WriteLine(
            $"Original object has the same values as the deserialized object: {valuesAreTheSame}")

Powyższy kod:

  • Obiekt Appointment jest tworzone i przypisywane do zmiennej appointment .
  • Wystąpienie appointment jest serializowane do formatu JSON przy użyciu polecenia JsonSerializer.Serialize.
  • Wynikowy kod JSON jest zapisywany w konsoli programu .
  • Kod JSON jest deserializowany z powrotem do nowego wystąpienia Appointment typu przy użyciu polecenia JsonSerializer.Deserialize.
  • Oryginalne i nowo zdeserializowane wystąpienia są porównywane pod kątem równości.
  • Wynik porównania jest zapisywany w konsoli programu .

Aby uzyskać więcej informacji, zobacz Jak serializować i deserializować dane JSON na platformie .NET.

Praca z elementem TimeSpan i DateTime

TimeOnly można utworzyć na podstawie elementu i przekonwertować na TimeSpanelement . TimeOnly Można również użyć z elementem DateTime, aby utworzyć TimeOnly wystąpienie lub utworzyć DateTime wystąpienie tak długo, jak podano datę.

Poniższy przykład tworzy TimeOnly obiekt z TimeSpanobiektu , a następnie konwertuje go z powrotem:

// TimeSpan must in the range of 00:00:00.0000000 to 23:59:59.9999999
var theTime = TimeOnly.FromTimeSpan(new TimeSpan(23, 59, 59));
var theTimeSpan = theTime.ToTimeSpan();

Console.WriteLine($"Variable '{nameof(theTime)}' is {theTime}");
Console.WriteLine($"Variable '{nameof(theTimeSpan)}' is {theTimeSpan}");

/* This example produces the following output:
 * 
 * Variable 'theTime' is 11:59 PM
 * Variable 'theTimeSpan' is 23:59:59
*/
' TimeSpan must in the range of 00:00:00.0000000 to 23:59:59.9999999
Dim theTime = TimeOnly.FromTimeSpan(New TimeSpan(23, 59, 59))
Dim theTimeSpan = theTime.ToTimeSpan()

Console.WriteLine($"Variable '{NameOf(theTime)}' is {theTime}")
Console.WriteLine($"Variable '{NameOf(theTimeSpan)}' is {theTimeSpan}")

' This example produces the following output
' 
' Variable 'theTime' is 11:59 PM
' Variable 'theTimeSpan' is 23:59:59

Poniższy przykład tworzy obiekt DateTime na podstawie TimeOnly obiektu z wybraną dowolną datą:

var theTime = new TimeOnly(11, 25, 46);   // 11:25 AM and 46 seconds
var theDate = new DateOnly(2015, 10, 21); // October 21, 2015
var theDateTime = theDate.ToDateTime(theTime);
var reverseTime = TimeOnly.FromDateTime(theDateTime);

Console.WriteLine($"Date only is {theDate}");
Console.WriteLine($"Time only is {theTime}");
Console.WriteLine();
Console.WriteLine($"Combined to a DateTime type, the value is {theDateTime}");
Console.WriteLine($"Converted back from DateTime, the time is {reverseTime}");

/* This example produces the following output:
 * 
 * Date only is 10/21/2015
 * Time only is 11:25 AM
 * 
 * Combined to a DateTime type, the value is 10/21/2015 11:25:46 AM
 * Converted back from DateTime, the time is 11:25 AM
*/
Dim theTime = New TimeOnly(11, 25, 46) ' 11:   25 PM And 46 seconds
Dim theDate = New DateOnly(2015, 10, 21) ' October 21, 2015
Dim theDateTime = theDate.ToDateTime(theTime)
Dim reverseTime = TimeOnly.FromDateTime(theDateTime)

Console.WriteLine($"Date only is {theDate}")
Console.WriteLine($"Time only is {theTime}")
Console.WriteLine()
Console.WriteLine($"Combined to a DateTime type, the value is {theDateTime}")
Console.WriteLine($"Converted back from DateTime, the time is {reverseTime}")

' This example produces the following output
' 
' Date only is 10/21/2015
' Time only is 11:25 AM
' 
' Combined to a DateTime type, the value is 10/21/2015 11:25:46 AM
' Converted back from DateTime, the time is 11:25 AM

Operatory arytmetyczne i porównanie timeOnly

Dwa TimeOnly wystąpienia można porównać ze sobą i można użyć IsBetween metody , aby sprawdzić, czy czas występuje między dwoma innymi razy. Gdy operator dodawania lub odejmowania jest używany w obiekcie TimeOnly, TimeSpan jest zwracany, reprezentując czas trwania.

var start = new TimeOnly(10, 12, 01); // 10:12:01 AM
var end = new TimeOnly(14, 00, 53); // 02:00:53 PM

var outside = start.AddMinutes(-3);
var inside = start.AddMinutes(120);

Console.WriteLine($"Time starts at {start} and ends at {end}");
Console.WriteLine($" Is {outside} between the start and end? {outside.IsBetween(start, end)}");
Console.WriteLine($" Is {inside} between the start and end? {inside.IsBetween(start, end)}");
Console.WriteLine($" Is {start} less than {end}? {start < end}");
Console.WriteLine($" Is {start} greater than {end}? {start > end}");
Console.WriteLine($" Does {start} equal {end}? {start == end}");
Console.WriteLine($" The time between {start} and {end} is {end - start}");

/* This example produces the following output:
 * 
 * Time starts at 10:12 AM and ends at 2:00 PM
 *  Is 10:09 AM between the start and end? False
 *  Is 12:12 PM between the start and end? True
 *  Is 10:12 AM less than 2:00 PM? True
 *  Is 10:12 AM greater than 2:00 PM? False
 *  Does 10:12 AM equal 2:00 PM? False
 *  The time between 10:12 AM and 2:00 PM is 03:48:52
*/
Dim startDate = New TimeOnly(10, 12, 1) ' 10:12:01 AM
Dim endDate = New TimeOnly(14, 0, 53) ' 02:00:53 PM

Dim outside = startDate.AddMinutes(-3)
Dim inside = startDate.AddMinutes(120)

Console.WriteLine($"Time starts at {startDate} and ends at {endDate}")
Console.WriteLine($" Is {outside} between the start and end? {outside.IsBetween(startDate, endDate)}")
Console.WriteLine($" Is {inside} between the start and end? {inside.IsBetween(startDate, endDate)}")
Console.WriteLine($" Is {startDate} less than {endDate}? {startDate < endDate}")
Console.WriteLine($" Is {startDate} greater than {endDate}? {startDate > endDate}")
Console.WriteLine($" Does {startDate} equal {endDate}? {startDate = endDate}")
Console.WriteLine($" The time between {startDate} and {endDate} is {endDate - startDate}")

' This example produces the following output
' 
' Time starts at 10:12 AM And ends at 2:00 PM
'  Is 10:09 AM between the start And end? False
'  Is 12:12 PM between the start And end? True
'  Is 10:12 AM less than 2:00 PM? True
'  Is 10:12 AM greater than 2:00 PM? False
'  Does 10:12 AM equal 2:00 PM? False
'  The time between 10:12 AM and 2:00 PM is 03:48:52