处理日期和时间是任何软件系统的一个重要方面,无论您是记录事件、计算时差还是安排任务。在 .NET 中,使用日期和时间数据的范围可以从简单到高度复杂,具体取决于您的用例。
在 .NET 中,日期和时间操作围绕几个基本类型:
这些类型中的每一种都适用于不同的方案。了解何时以及如何使用它们对于构建强大的应用程序至关重要。
该结构是 .NET 中使用最广泛的类,用于表示日期和时间。它将日期和时间信息封装到毫秒。DateTime
下面是一个创建对象的示例:DateTime
DateTime now = DateTime.Now; // Current local date and time
DateTime utcNow = DateTime.UtcNow; // Current UTC date and time
DateTime specificDate = new DateTime(2023, 9, 30, 14, 30, 0); // A specific date and time
您可以使用 和 等方法轻松添加或减去天数、小时或其他时间间隔。.AddDays().AddHours()
DateTime tomorrow = now.AddDays(1);
DateTime nextHour = now.AddHours(1);
向用户显示日期时,将对象格式化为字符串是一项常见的操作。该方法允许自定义格式。DateTimeToString
string formattedDate = now.ToString("yyyy-MM-dd HH:mm:ss");
虽然非常有用,但它有一个明显的限制:它不能很好地处理时区。如果您的应用程序需要跨不同地理区域管理时间,则单独管理可能会引入错误或意外行为。这就是发挥作用的地方。DateTimeDateTimeDateTimeOffset
该类型通过包含与 UTC 的偏移量进行扩展,从而更轻松地使用时区。当您不仅需要跟踪时间,还需要跟踪与 UTC 的差异时,此结构非常有用。DateTimeOffsetDateTime
DateTimeOffset currentTimeWithOffset = DateTimeOffset.Now; // Current time with the system's time zone offset
DateTimeOffset specificTimeWithOffset = new DateTimeOffset(2023, 9, 30, 14, 30, 0, TimeSpan.FromHours(-5)); // Specific time with a -5 hours offset from UTC
DateTimeOffset当您需要存储或传输时间同时跟踪时区或偏移量时,它特别有用。例如,如果您在纽约记录一个事件,在东京记录另一个事件,则需要确保两个时间戳都反映正确的本地时间和 UTC 偏移量。
DateTimeOffset eventTimeInNY = new DateTimeOffset(2023, 9, 30, 9, 0, 0, TimeSpan.FromHours(-4)); // NY (UTC-4)
DateTimeOffset eventTimeInTokyo = new DateTimeOffset(2023, 9, 30, 23, 0, 0, TimeSpan.FromHours(9)); // Tokyo (UTC+9)
此类型通过显式管理 UTC 偏移量来确保跨时区的一致性。
该结构表示持续时间,而不是特定的时间点。当您需要计算 2 或 值之间的差值,或者需要表示经过的时间时,这非常有用。TimeSpanDateTimeDateTimeOffset
TimeSpan duration = new TimeSpan(1, 30, 0); // 1 hour, 30 minutes, 0 seconds
DateTime endTime = now.Add(duration);
您可以减去 2 或 对象,以获得表示它们之间的差异的 a。DateTimeDateTimeOffsetTimeSpan
TimeSpan difference = endTime - now;
Console.WriteLine($"The time difference is {difference.TotalMinutes} minutes.");
这对于计算特定任务的持续时间、事件间隔或剩余时间特别有用。
在 .NET 6 中引入,提供了一种更直观、更简洁的方式来处理您只关心日期或时间的情况,而没有任何时区或偏移量复杂性。DateOnlyTimeOnly
DateOnly birthDate = new DateOnly(1990, 5, 20);
Console.WriteLine(birthDate.ToString()); // Outputs: 05/20/1990
TimeOnly meetingTime = new TimeOnly(14, 30); // 2:30 PM
Console.WriteLine(meetingTime.ToString()); // Outputs: 14:30
该类是 .NET 8 的最新添加,它提供了时间抽象,允许您在单元测试中模拟或模拟时间。这解决了测试基于时间的功能时的一个常见问题。TimeProvider
要将类用于自定义时间模拟:TimeProvider
TimeProvider provider = TimeProvider.System; // Use the system's time
DateTimeOffset currentTime = provider.GetUtcNow(); // Get current UTC time
您还可以为单元测试场景创建虚构实现,以模拟不同的时间点。TimeProvider
这种抽象实现了更好的可测试性,消除了对 or 的依赖,这可能会导致不稳定的测试。DateTime.NowDateTimeOffset.Now
Unix 时间戳表示自 1970 年 1 月 1 日 (UTC) 以来的秒数,经常用于系统和 API。.NET 提供内置支持,用于将 Unix 时间戳转换为 Unix 时间戳,反之亦然。DateTimeOffset
long unixTime = 1625072400; // Example Unix timestamp
DateTimeOffset dateTime = DateTimeOffset.FromUnixTimeSeconds(unixTime);
Console.WriteLine(dateTime); // Outputs: 30/06/2021 12:00:00 PM +00:00
DateTimeOffset now = DateTimeOffset.UtcNow;
long unixTimeNow = now.ToUnixTimeSeconds();
Console.WriteLine(unixTimeNow);
此转换可帮助您与使用 Unix 时间戳的外部系统无缝协作。
虽然 .NET 提供了用于处理日期和时间的可靠内置工具,但复杂的应用程序可能会受益于 NodaTime,这是一个旨在处理日期和时间的综合库,尤其是在涉及多个时区或不同日历的情况下。
var clock = SystemClock.Instance.GetCurrentInstant();
DateTimeZone timeZone = DateTimeZoneProviders.Tzdb["America/New_York"];
ZonedDateTime nyTime = clock.InZone(timeZone);
Console.WriteLine(nyTime); // Outputs current time in New York
当您需要管理全球时区或使用非公历时,NodaTime 特别有用。
闰年和闰日会带来复杂性,尤其是在计算持续时间、延长合同或确定某人的年龄时。.NET 有助于无缝处理这些情况。
DateTime birthday = new DateTime(2000, 2, 29); // Leap year birthday
DateTime today = DateTime.Today;
int age = today.Year - birthday.Year;
// Adjust if the birthday hasn't occurred yet this year
if (birthday > today.AddYears(-age)) age--;
Console.WriteLine($"The person is {age} years old.");
尽管 .NET 提供了灵活性,但使用日期和时间仍然存在挑战。以下是一些常见的陷阱以及如何避免它们:
处理时区和 DST 更改可能很棘手。跨不同时区安排时,请始终考虑:
DateTime utcTimestamp = DateTime.UtcNow;
如果格式定义不明确,则从用户输入或外部数据源解析日期可能会导致错误。在解析字符串时,请始终指定预期的格式,以避免异常。
string dateStr = "30-09-2023";
DateTime parsedDate = DateTime.ParseExact(dateStr, "dd-MM-yyyy", CultureInfo.InvariantCulture);
比较日期或时间时,请确保在相同的基础上进行比较(例如,均采用 UTC 或均采用当地时间)。
bool isSameMoment = DateTime.UtcNow == someOtherDateTime.ToUniversalTime();