Поделиться через


System.TimeSpan структура

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

Объект TimeSpan представляет интервал времени (длительность времени или истекшего времени), измеряемый как положительное или отрицательное количество дней, часов, минут, секунд и долей секунды. Структура TimeSpan также может использоваться для представления времени дня, но только в том случае, если время не связано с определенной датой. В противном случае вместо этого следует использовать структуру DateTime или DateTimeOffset. (Дополнительные сведения об использовании структуры TimeSpan для отражения времени дня см. в выборе между DateTime, DateTimeOffset, TimeSpan и TimeZoneInfo.)

Примечание.

Значение TimeSpan представляет интервал времени и может быть выражено как определенное количество дней, часов, минут, секунд и миллисекунд. Поскольку он представляет общий интервал без ссылки на определенную начальную или конечную точку, она не может быть выражена с точки зрения лет и месяцев, оба из которых имеют переменное число дней. Он отличается от значения DateTime, представляющего дату и время без ссылки на определенный часовой пояс или значение DateTimeOffset, представляющее определенный момент времени.

Самая большая единица времени, которую использует структура TimeSpan для измерения длительности, это день. Интервалы времени измеряются в днях для согласованности, так как количество дней в больших единицах времени, таких как месяцы и годы, меняется.

Значение объекта TimeSpan — это число тиков, равных представленному интервалу времени. Тик равен 100 наносекундам или одной десятимиллионной секунды. Значение объекта TimeSpan может варьироваться от TimeSpan.MinValue до TimeSpan.MaxValue.

Создание экземпляра значения TimeSpan

Можно создать экземпляр значения TimeSpan несколькими способами:

  • Вызывая неявный конструктор без параметров. При этом создается объект, значение которого TimeSpan.Zero, как показано в следующем примере.

    TimeSpan interval = new TimeSpan();
    Console.WriteLine(interval.Equals(TimeSpan.Zero));    // Displays "True".
    
    let interval = TimeSpan()
    printfn $"{interval.Equals TimeSpan.Zero}"    // Displays "True".
    
    Dim interval As New TimeSpan()
    Console.WriteLine(interval.Equals(TimeSpan.Zero))     ' Displays "True".
    
  • Вызывая один из его явных конструкторов. В следующем примере значение TimeSpan устанавливается в указанное количество часов, минут и секунд.

    TimeSpan interval = new TimeSpan(2, 14, 18);
    Console.WriteLine(interval.ToString());              
    
    // Displays "02:14:18".
    
    let interval = TimeSpan(2, 14, 18)
    printfn $"{interval}"              
    
    // Displays "02:14:18".
    
    Dim interval As New TimeSpan(2, 14, 18)
    Console.WriteLine(interval.ToString())                ' Displays "02:14:18".
    
  • Вызывая метод или выполняя операцию, возвращающую значение TimeSpan. Например, можно создать экземпляр значения TimeSpan, представляющего интервал между двумя значениями даты и времени, как показано в следующем примере.

    DateTime departure = new DateTime(2010, 6, 12, 18, 32, 0);
    DateTime arrival = new DateTime(2010, 6, 13, 22, 47, 0);
    TimeSpan travelTime = arrival - departure;  
    Console.WriteLine($"{arrival} - {departure} = {travelTime}");      
    
    // The example displays the following output:
    //       6/13/2010 10:47:00 PM - 6/12/2010 6:32:00 PM = 1.04:15:00
    
    let departure = DateTime(2010, 6, 12, 18, 32, 0)
    let arrival = DateTime(2010, 6, 13, 22, 47, 0)
    let travelTime = arrival - departure  
    printfn $"{arrival} - {departure} = {travelTime}"
    
    // The example displays the following output:
    //       6/13/2010 10:47:00 PM - 6/12/2010 6:32:00 PM = 1.04:15:00
    
    Dim departure As DateTime = #06/12/2010 6:32PM#
    Dim arrival As DateTime = #06/13/2010 10:47PM#
    Dim travelTime As TimeSpan = arrival - departure
    Console.WriteLine("{0} - {1} = {2}", arrival, departure, travelTime)
    ' The example displays the following output:
    '       6/13/2010 10:47:00 PM - 6/12/2010 6:32:00 PM = 1.04:15:00
    

    Вы также можете инициализировать объект TimeSpan до нулевого значения времени таким образом, как показано в следующем примере.

    Random rnd = new Random();
    
    TimeSpan timeSpent = TimeSpan.Zero;
    
    timeSpent += GetTimeBeforeLunch();
    timeSpent += GetTimeAfterLunch();
    
    Console.WriteLine($"Total time: {timeSpent}");
    
    TimeSpan GetTimeBeforeLunch()
    {
        return new TimeSpan(rnd.Next(3, 6), 0, 0);
    }
    
    TimeSpan GetTimeAfterLunch()
    {
        return new TimeSpan(rnd.Next(3, 6), 0, 0);
    }
    
    // The example displays output like the following:
    //        Total time: 08:00:00
    
    open System
    
    let rnd = Random()
    
    let getTimeBeforeLunch () =
        TimeSpan(rnd.Next(3, 6), 0, 0)
    
    let getTimeAfterLunch() =
        TimeSpan(rnd.Next(3, 6), 0, 0)
    
    do
        let timeSpent = TimeSpan.Zero
    
        let timeSpent = timeSpent + getTimeBeforeLunch ()
        let timeSpent = timeSpent + getTimeAfterLunch ()
    
        printfn $"Total time: {timeSpent}"
    
    
    // The example displays output like the following:
    //        Total time: 08:00:00
    
    Module Example
       Dim rnd As New Random()
       
       Public Sub Main()
          Dim timeSpent As TimeSpan = TimeSpan.Zero
    
          timeSpent += GetTimeBeforeLunch()
          timeSpent += GetTimeAfterLunch()
    
          Console.WriteLine("Total time: {0}", timeSpent)
       End Sub
       
       Private Function GetTimeBeforeLunch() As TimeSpan
          Return New TimeSpan(rnd.Next(3, 6), 0, 0)
       End Function
       
       Private Function GetTimeAfterLunch() As TimeSpan
          Return New TimeSpan(rnd.Next(3, 6), 0, 0)
       End Function
    End Module
    ' The example displays output like the following:
    '       Total time: 08:00:00
    

    Значения TimeSpan возвращаются арифметическими операторами и методами структур DateTime, DateTimeOffsetи TimeSpan.

  • Анализируя строковое представление значения TimeSpan. Методы Parse и TryParse можно использовать для преобразования строк, содержащих интервалы времени в значения TimeSpan. В следующем примере метод Parse используется для преобразования массива строк в TimeSpan значений.

    string[] values = { "12", "31.", "5.8:32:16", "12:12:15.95", ".12"};
    foreach (string value in values)
    {
       try {
          TimeSpan ts = TimeSpan.Parse(value);
          Console.WriteLine($"'{value}' --> {ts}");
       }
       catch (FormatException) {
          Console.WriteLine($"Unable to parse '{value}'");
       }
       catch (OverflowException) {
          Console.WriteLine($"'{value}' is outside the range of a TimeSpan.");
       }   
    }
    
    // The example displays the following output:
    //       '12' --> 12.00:00:00
    //       Unable to parse '31.'
    //       '5.8:32:16' --> 5.08:32:16
    //       '12:12:15.95' --> 12:12:15.9500000
    //       Unable to parse '.12'
    
    let values = [| "12"; "31."; "5.8:32:16"; "12:12:15.95"; ".12" |]
    for value in values do
        try
            let ts = TimeSpan.Parse value
            printfn $"'{value}' --> {ts}"
        with 
        | :? FormatException ->
            printfn $"Unable to parse '{value}'"
        | :? OverflowException ->
            printfn $"'{value}' is outside the range of a TimeSpan."
    
    // The example displays the following output:
    //       '12' --> 12.00:00:00
    //       Unable to parse '31.'
    //       '5.8:32:16' --> 5.08:32:16
    //       '12:12:15.95' --> 12:12:15.9500000
    //       Unable to parse '.12'
    
    Dim values() As String = {"12", "31.", "5.8:32:16", "12:12:15.95", ".12"}
    For Each value As String In values
        Try
            Dim ts As TimeSpan = TimeSpan.Parse(value)
            Console.WriteLine("'{0}' --> {1}", value, ts)
        Catch e As FormatException
            Console.WriteLine("Unable to parse '{0}'", value)
        Catch e As OverflowException
            Console.WriteLine("'{0}' is outside the range of a TimeSpan.", value)
        End Try
    Next
    ' The example displays the following output:
    '       '12' --> 12.00:00:00
    '       Unable to parse '31.'
    '       '5.8:32:16' --> 5.08:32:16
    '       '12:12:15.95' --> 12:12:15.9500000
    '       Unable to parse '.12'
    

    Кроме того, можно определить точный формат входной строки для анализа и преобразования в значение TimeSpan путем вызова метода ParseExact или TryParseExact.

Выполнение операций со значениями TimeSpan

Вы можете добавлять и вычитать продолжительность времени с помощью операторов Addition и Subtraction или вызова методов Add и Subtract. Кроме того, можно сравнить два периода времени, вызвав методы Compare, CompareToи Equals. Структура TimeSpan также включает методы Duration и Negate, которые преобразуют интервалы времени в положительные и отрицательные значения,

Диапазон значений TimeSpan от MinValue до MaxValue.

Форматирование значения TimeSpan

Значение TimeSpan можно представить как [-]d.hh:mm:ss.ff, где необязательный знак минуса указывает отрицательный интервал времени, d компонентом равен дням, hh это часы, как на 24-часовых часах, mm это минуты, ss это секунды, и ff это доли секунды. То есть интервал времени состоит из положительного или отрицательного числа дней без времени дня, или числа дней с временем дня или только временем дня.

Начиная с .NET Framework 4, структура TimeSpan поддерживает форматирование с учётом культурных особенностей через перегрузки метода ToString, который преобразует значение TimeSpan в его строковое представление. Метод по умолчанию TimeSpan.ToString() возвращает интервал времени с помощью инвариантного формата, идентичного возвращаемого значения в предыдущих версиях .NET Framework. Перегрузка TimeSpan.ToString(String) позволяет указать строку формата, которая определяет строковое представление интервала времени. Перегрузка TimeSpan.ToString(String, IFormatProvider) позволяет указать строку формата и культуру, соглашения о форматировании которой используются для создания строкового представления интервала времени. TimeSpan поддерживает как стандартные, так и пользовательские строки форматирования. Дополнительные сведения можно найти в стандартных строках формата TimeSpan и настраиваемых строках формата TimeSpan. Однако только стандартные строки форматирования чувствительны к языковым и региональным параметрам.

Восстановление устаревшего форматирования TimeSpan

В некоторых случаях код, который успешно форматировал значения TimeSpan в .NET Framework 3.5 и более ранних версиях, перестает работать в .NET Framework 4. Это наиболее часто встречается в коде, который вызывает метод элемента <TimeSpan_LegacyFormatMode> для форматирования значения TimeSpan при помощи строки форматирования. Следующий пример успешно форматирует значение TimeSpan в .NET Framework 3.5 и более ранних версиях, но создает исключение в .NET Framework 4 и более поздних версиях. Обратите внимание, что он пытается отформатировать значение TimeSpan с помощью неподдерживаемого описателя формата, который игнорируется в .NET Framework 3.5 и более ранних версиях.

ShowFormattingCode();
// Output from .NET Framework 3.5 and earlier versions:
//       12:30:45
// Output from .NET Framework 4:
//       Invalid Format    

Console.WriteLine("---");

ShowParsingCode();
// Output:
//       000000006 --> 6.00:00:00

void ShowFormattingCode()
{
    TimeSpan interval = new TimeSpan(12, 30, 45);
    string output;
    try
    {
        output = String.Format("{0:r}", interval);
    }
    catch (FormatException)
    {
        output = "Invalid Format";
    }
    Console.WriteLine(output);
}

void ShowParsingCode()
{
    string value = "000000006";
    try
    {
        TimeSpan interval = TimeSpan.Parse(value);
        Console.WriteLine($"{value} --> {interval}");
    }
    catch (FormatException)
    {
        Console.WriteLine($"{value}: Bad Format");
    }
    catch (OverflowException)
    {
        Console.WriteLine($"{value}: Overflow");
    }
}
let showFormattingCode () =
    let interval = TimeSpan(12, 30, 45)
    try
        $"{interval:r}"
    with :? FormatException ->
        "Invalid Format"
    |> printfn "%s"

let showParsingCode () =
    let value = "000000006"
    try
        let interval = TimeSpan.Parse value
        printfn $"{value} --> {interval}"
    with
    | :? FormatException ->
        printfn $"{value}: Bad Format"
    | :? OverflowException ->
        printfn $"{value}: Overflow"

showFormattingCode ()
// Output from .NET Framework 3.5 and earlier versions:
//       12:30:45
// Output from .NET Framework 4:
//       Invalid Format    

printfn "---"

showParsingCode ()
// Output:
//       000000006 --> 6.00:00:00
Dim interval As New TimeSpan(12, 30, 45)
Dim output As String
Try
    output = String.Format("{0:r}", interval)
Catch e As FormatException
    output = "Invalid Format"
End Try
Console.WriteLine(output)
' Output from .NET Framework 3.5 and earlier versions:
'       12:30:45
' Output from .NET Framework 4:
'       Invalid Format

Если вы не можете изменить код, можно восстановить устаревшее форматирование значений TimeSpan одним из следующих способов:

  • Создав файл конфигурации, содержащий элемент <TimeSpan_LegacyFormatMode>. Установка атрибута enabled этого элемента в true восстанавливает устаревшее форматирование TimeSpan для каждого приложения.

  • Настроив переключатель совместимости "NetFx40_TimeSpanLegacyFormatMode" при создании домена приложения. Это позволяет использовать устаревшее форматирование TimeSpan в рамках каждого домена приложений. В следующем примере создается домен приложения, использующий устаревшее форматирование "TimeSpan".

    using System;
    
    public class Example2
    {
        public static void Main()
        {
            AppDomainSetup appSetup = new AppDomainSetup();
            appSetup.SetCompatibilitySwitches(new string[] { "NetFx40_TimeSpanLegacyFormatMode" });
            AppDomain legacyDomain = AppDomain.CreateDomain("legacyDomain",
                                                            null, appSetup);
            legacyDomain.ExecuteAssembly("ShowTimeSpan.exe");
        }
    }
    
    open System
    
    let appSetup = AppDomainSetup()
    appSetup.SetCompatibilitySwitches [| "NetFx40_TimeSpanLegacyFormatMode" |]
    let legacyDomain = AppDomain.CreateDomain("legacyDomain", null, appSetup)
    legacyDomain.ExecuteAssembly "ShowTimeSpan.exe" |> ignore
    
    Module Example3
        Public Sub Main()
            Dim appSetup As New AppDomainSetup()
            appSetup.SetCompatibilitySwitches({"NetFx40_TimeSpanLegacyFormatMode"})
            Dim legacyDomain As AppDomain = AppDomain.CreateDomain("legacyDomain",
                                                                 Nothing, appSetup)
            legacyDomain.ExecuteAssembly("ShowTimeSpan.exe")
        End Sub
    End Module
    

    Когда следующий код выполняется в новом домене приложения, он возвращает устаревшее поведение форматирования TimeSpan.

    using System;
    
    public class Example3
    {
       public static void Main()
       {
          TimeSpan interval = DateTime.Now - DateTime.Now.Date;
          string msg = String.Format("Elapsed Time Today: {0:d} hours.",
                                     interval);
          Console.WriteLine(msg);
       }
    }
    // The example displays the following output:
    //       Elapsed Time Today: 01:40:52.2524662 hours.
    
    open System
    
    let interval = DateTime.Now - DateTime.Now.Date
    printfn $"Elapsed Time Today: {interval:d} hours."
    // The example displays the following output:
    //       Elapsed Time Today: 01:40:52.2524662 hours.
    
    Module Example4
        Public Sub Main()
            Dim interval As TimeSpan = Date.Now - Date.Now.Date
            Dim msg As String = String.Format("Elapsed Time Today: {0:d} hours.",
                                             interval)
            Console.WriteLine(msg)
        End Sub
    End Module
    ' The example displays output like the following:
    '       Elapsed Time Today: 01:40:52.2524662 hours.