簡介
TimeSpan 是 .NET 中用於表示時間間隔或持續時間的重要結構體。它提供了豐富的方法和屬性來處理時間跨度,從幾毫秒到幾百萬天都可以精確表示。
概念與特性
TimeSpan 表示一個時間間隔(時間段),而不是具體的時間點。
| 特性 | 説明 |
|---|---|
| 命名空間 | System |
| 結構類型 | struct(值類型) |
| 表示範圍 | 約 ±10,675,199 天(≈29,000 年) |
| 精度 | 1 Tick = 100 納秒 |
| 單位表示 | 可用天、小時、分鐘、秒、毫秒、Ticks |
與 DateTime 區別:
DateTime表示一個具體的時間點(例如:2025-09-18 08:00)。TimeSpan表示一個時間間隔(例如:2 小時 30 分鐘)。
創建 TimeSpan
構造函數
// 構造函數:TimeSpan(days, hours, minutes, seconds)
var span1 = new TimeSpan(1, 2, 30, 0); // 1天2小時30分0秒
// 構造函數:TimeSpan(hours, minutes, seconds)
var span2 = new TimeSpan(2, 30, 0); // 2小時30分
靜態工廠方法
推薦使用靜態方法,可讀性更高:
TimeSpan ts1 = TimeSpan.FromDays(1.5); // 1.5天
TimeSpan ts2 = TimeSpan.FromHours(2.5); // 2.5小時
TimeSpan ts3 = TimeSpan.FromMinutes(90); // 90分鐘
TimeSpan ts4 = TimeSpan.FromSeconds(45); // 45秒
TimeSpan ts5 = TimeSpan.FromMilliseconds(500); // 500毫秒
TimeSpan ts6 = TimeSpan.FromTicks(5000); // 5000 Ticks
解析字符串
TimeSpan ts = TimeSpan.Parse("1.02:30:00");
// 格式:d.hh:mm:ss -> 1天2小時30分
或安全解析:
if (TimeSpan.TryParse("02:15", out var result))
Console.WriteLine(result); // 02:15:00
常用屬性
| 屬性 | 説明 | 示例 |
|---|---|---|
Days |
總天數(整數部分) | ts.Days |
Hours |
小時(0–23) | ts.Hours |
Minutes |
分鐘(0–59) | ts.Minutes |
Seconds |
秒(0–59) | ts.Seconds |
Milliseconds |
毫秒(0–999) | ts.Milliseconds |
Ticks |
以 Tick(100ns)為單位 | ts.Ticks |
TotalDays |
總天數(含小數) | ts.TotalDays |
TotalHours |
總小時數(含小數) | ts.TotalHours |
TotalMinutes |
總分鐘數(含小數) | ts.TotalMinutes |
TotalSeconds |
總秒數(含小數) | ts.TotalSeconds |
TotalMilliseconds |
總毫秒數 | ts.TotalMilliseconds |
區別
Days、Hours等返回整數部分(對應分量)。TotalDays、TotalHours等返回完整總量。
示例:
var ts = new TimeSpan(1, 2, 30, 0);
Console.WriteLine(ts.Days); // 1
Console.WriteLine(ts.TotalHours); // 26.5
運算操作
加減
var t1 = TimeSpan.FromHours(3);
var t2 = TimeSpan.FromMinutes(30);
TimeSpan sum = t1 + t2; // 3:30:00
TimeSpan diff = t1 - t2; // 2:30:00
乘除
TimeSpan doubleTime = TimeSpan.FromMinutes(45) * 2; // 1:30:00
TimeSpan halfTime = TimeSpan.FromHours(4) / 2; // 2:00:00
C# 11 之前不支持直接乘除,需要用 TimeSpan.FromTicks() 手動計算。
(.NET 7 / C# 11 起支持 * / 運算符)
比較
TimeSpan ts1 = TimeSpan.FromHours(2);
TimeSpan ts2 = TimeSpan.FromMinutes(120); // 也是2小時
// 比較
bool isEqual = ts1 == ts2; // true
bool isNotEqual = ts1 != ts2; // false
bool isGreater = ts1 > TimeSpan.FromHours(1); // true
bool isLess = ts1 < TimeSpan.FromHours(3); // true
// 比較方法
int compareResult = ts1.CompareTo(ts2); // 0 (相等)
bool equals = ts1.Equals(ts2); // true
取絕對值
var negative = TimeSpan.FromHours(-5);
var positive = negative.Duration(); // 05:00:00
取負值
var neg = -TimeSpan.FromMinutes(30); // -00:30:00
與 DateTime 配合
TimeSpan 常用於計算兩個時間點的差值:
DateTime start = DateTime.Now;
// 模擬一些操作
System.Threading.Thread.Sleep(1500);
DateTime end = DateTime.Now;
TimeSpan elapsed = end - start;
Console.WriteLine($"執行耗時: {elapsed.TotalMilliseconds} ms");
也可以用來加減時間:
DateTime tomorrow = DateTime.Now + TimeSpan.FromDays(1);
格式化輸出
默認格式
Console.WriteLine(ts.ToString()); // "1.02:30:00" (d.hh:mm:ss)
標準格式
Console.WriteLine(ts.ToString("c")); // 同上 (常數格式)
Console.WriteLine(ts.ToString("g")); // 1:2:30:45.5 (常規短格式)
Console.WriteLine(ts.ToString("G")); // 1:02:30:45.5000000 (常規長格式)
自定義格式
ToString 支持標準和自定義格式:
var ts = new TimeSpan(1, 2, 30, 45, 500);
Console.WriteLine(ts.ToString(@"hh\:mm\:ss")); // 02:30:45
Console.WriteLine(ts.ToString(@"d\.hh\:mm\:ss\.fff")); // 1.02:30:45.500
需要轉義 : 和 .
常用靜態字段
| 字段 | 説明 |
|---|---|
TimeSpan.Zero |
表示 0 |
TimeSpan.MaxValue |
最大可表示值 |
TimeSpan.MinValue |
最小可表示值 |
典型使用場景
定時任務/超時控制
var timeout = TimeSpan.FromSeconds(30);
var cts = new CancellationTokenSource(timeout);
統計程序耗時
var watch = System.Diagnostics.Stopwatch.StartNew();
// do work
watch.Stop();
Console.WriteLine(watch.Elapsed); // TimeSpan
實際應用示例
using System;
class Program
{
static void Main()
{
DateTime start = DateTime.Now;
// 模擬任務
System.Threading.Thread.Sleep(1200);
DateTime end = DateTime.Now;
TimeSpan span = end - start;
Console.WriteLine($"耗時: {span.TotalMilliseconds} 毫秒");
Console.WriteLine($"格式化: {span.ToString(@"hh\:mm\:ss\.fff")}");
Console.WriteLine($"天: {span.Days}, 小時: {span.Hours}, 總小時: {span.TotalHours:F2}");
}
}
輸出示例:
耗時: 1203.45 毫秒
格式化: 00:00:01.203
天: 0, 小時: 0, 總小時: 0.00
高級用法
自定義 TimeSpan 擴展方
public static class TimeSpanExtensions
{
public static string ToHumanReadableString(this TimeSpan timeSpan)
{
if (timeSpan.TotalDays >= 1)
return $"{(int)timeSpan.TotalDays} 天 {timeSpan.Hours} 小時";
if (timeSpan.TotalHours >= 1)
return $"{(int)timeSpan.TotalHours} 小時 {timeSpan.Minutes} 分鐘";
if (timeSpan.TotalMinutes >= 1)
return $"{(int)timeSpan.TotalMinutes} 分鐘 {timeSpan.Seconds} 秒";
if (timeSpan.TotalSeconds >= 1)
return $"{(int)timeSpan.TotalSeconds} 秒";
return $"{timeSpan.Milliseconds} 毫秒";
}
}
// 使用擴展方法
TimeSpan ts = TimeSpan.FromHours(2.5);
Console.WriteLine(ts.ToHumanReadableString()); // 輸出: 2 小時 30 分鐘
注意事項和最佳實踐
- 不可變性:
TimeSpan是值類型且不可變,所有操作都返回新的TimeSpan實例 - 精度考慮:
TimeSpan使用ticks(100 納秒)作為內部存儲,提供高精度但需要注意浮點運算的精度問題 - 文化敏感性:解析和格式化
TimeSpan時,注意當前線程的文化設置 - 性能考慮:對於高性能場景,考慮使用
Stopwatch而不是DateTime減法來計算時間間隔