System.TimeSpan 结构

本文提供了此 API 参考文档的补充说明。

对象 TimeSpan 表示一个时间间隔(持续时间或已用时间),该时间间隔以正数或负天数、小时数、分钟数、秒数和秒分数为单位。 该 TimeSpan 结构还可用于表示一天的时间,但前提是时间与特定日期无关。 否则,应使用 DateTimeDateTimeOffset 结构。 (有关使用 TimeSpan 结构反映一天的时间的详细信息,请参阅 “在 DateTime、DateTimeOffset、TimeSpan 和 TimeZoneInfo 之间进行选择”。)

注释

TimeSpan 表示时间间隔,可以表示为特定的天数、小时、分钟、秒和毫秒。 由于它表示不引用特定起点或终点的一般间隔,因此不能以年和月来表示,这两者都有可变天数。 它不同于一个 DateTime 值,该值表示不引用特定时区的日期和时间,或 DateTimeOffset 表示特定时间刻度的值。

结构用于度量持续时间的最大时间 TimeSpan 单位是一天。 时间间隔以天为单位来衡量一致性,因为以较大的时间单位(如月份和年份)的天数不同。

TimeSpan 对象的值是等于所表示的时间间隔的刻度数。 滴答值等于 100 纳秒,即一千万分之一秒。 TimeSpan 对象的值可以介于 TimeSpan.MinValueTimeSpan.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值由DateTimeDateTimeOffsetTimeSpan结构的算术运算符及方法返回。

  • 通过解析TimeSpan值的字符串表示形式。 可以使用 ParseTryParse 方法将包含时间间隔的字符串转换为 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'
    

    此外,还可以通过调用TimeSpanParseExact方法定义要分析并转换为TryParseExact值的输入字符串的精确格式。

对 TimeSpan 值执行操作

可以通过使用AdditionSubtraction运算符,或者调用AddSubtract方法来添加和减去时间持续时间。 还可以通过调用CompareCompareToEquals方法来比较两个持续时间。 该TimeSpan结构还包括将DurationNegate时间间隔转换为正值和负值的方法,

TimeSpan 值的范围是 MinValueMaxValue

格式化 TimeSpan 值

TimeSpan 可以表示为 [-]dhhmmssff,其中可选减号表示负时间间隔,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 格式

在某些情况下,能够在 .NET Framework 3.5 和更早版本中成功格式化 TimeSpan 值的代码在 .NET Framework 4 中会失败。 这是最常见的代码,它调用 <TimeSpan_LegacyFormatMode> 元素 方法来格式化 TimeSpan 具有格式字符串的值。 以下示例成功在 .NET Framework 3.5 及更早版本中格式化 TimeSpan 值,但在 .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.