C# 时间教程:何时、何事、如何

导航至

时间操作是编程的必备技能。这适用于你喜欢的任何编程语言:Python、Java、Kotlin、Ruby,等等。当然,C# 也不例外,这就是为什么我们今天为您带来了一篇关于 C# 时间操作的全面而易于理解的指南。

我们将首先从 C# 编程中时间处理的整体视角出发。之后,我们会进一步深入,为您提供更多可操作的技巧。您将了解 C# 中主要的时间相关函数——它们是什么以及如何使用它们。

在总结之前,我们将探讨 C# 中时间处理的实际应用,以便您知道如何使用本文中的信息以最有价值的方式为您的项目服务。

先决条件

如果您想跟随文章内容,边走边测试代码示例,您需要

  • 在您的机器上安装 .NET SDK 版本——我们推荐 .NET 7
  • 一些 IDE 或文本编辑器——Visual Studio Code 是一个不错的选择
  • 至少具备基本的 C# 知识

C# 编程中时间是如何使用的?

在 C# 和 .NET 中,时间处理是一等公民。为了让您的程序能够处理时间和日期,您不需要做任何特别的事情,例如添加使用语句或安装 NuGet 包。正如您将看到的,您需要的用于处理时间相关的类型都位于 System 命名空间中,您已经可以访问它们。

考虑到 C# 是一个(主要是)面向对象的编程语言,它的相关功能通过对象的使用提供也就不足为奇了。您将主要使用的是 DateTime类型。DateTime 类型是一个结构——也就是说,它是一个值类型而不是引用类型——它是不变的。由于其值永不改变,它可以以更安全、更可预测的方式使用,从而产生更健壮的代码。

DateTime 代表一个日期和时间。但它的接口也提供了许多有用的时间相关操作,例如

  • 执行时间算术,例如将分钟、小时、天数或其他时间段添加到给定日期
  • 比较两个日期
  • 根据多种数据和时间格式对日期进行格式化

尽管 DateTime 是 C# 中最著名的与时间相关的类型之一,但它远非唯一。其他有用的类型包括 DateTimeOffsetTimeSpanDateOnlyTimeOnlyTimeZoneInfo

现在让我们更深入地了解如何在实践中使用这些函数。

现在是时候学习如何在 C# 中实际使用时间相关功能了。在本节中,我们将使用 FAQ 格式。我们将列出常见场景作为问题,并立即回答。

如何在 C# 中获取当前时间?

在 C# 中获取当前时间和日期的最简单方法是使用 DateTime 类型的 Now 属性。它返回一个 DateTime 值,包含根据运行程序的系统的时钟显示的当前日期和时间。以下是一个简单的程序,它根据一天中的时间问候用户

DateTime currentTime = DateTime.Now;
int hour = currentTime.Hour;

if (hour >= 8 && hour < 12)
{
    Console.WriteLine("Good morning!");
} 
else if (hour >= 12 && hour < 18)
{
    Console.WriteLine("Good afternoon!");
}
else
{
    Console.WriteLine("Good evening!");
}

如您所见,代码还使用了返回的 DateTime 上的 Hour 属性,仅获取当前值的时部分。还有其他属性用于值的各个部分

int minute = currentTime.Minute;
int second = currentTime.Second;
int day = currentTime.Day;
int month = currentTime.Month;
int year = currentTime.Year;
int microsecond = currentTime.Microsecond;
int milisecond = currentTime.Millisecond;
int dayOfYear = currentTime.DayOfYear;

C# 中有时间数据类型吗?

在 C# 的大部分时间里,C# 没有提供仅用于时间的单一数据类型,也没有仅用于日期的单一数据类型。您必须满足于 DateTime –– 总是包含这两个组件 –– 这通常会导致错误,尤其是在比较场景中。(另一个选择是求助于第三方库,如 NodaTime。)

从 .NET 6 开始,现在有仅存储日期或时间的类型。它们分别称为 DateOnlyTimeOnly

这就是您如何检索当前时间并将其存储在 TimeOnly 变量中的方法

TimeOnly now = TimeOnly.FromDateTime(DateTime.Now);
DateOnly today = DateOnly.FromDateTime(DateTime.Now);

如何处理持续时间?

如果您有两个 DateTime 值,您可以轻松计算它们之间的差异(即差异)。结果是 TimeSpan 类型的值。让我们看看如何在实践中实现它

var start  = new DateTime(2023, 10, 5, 10, 0, 0);
var end = new DateTime(2023, 10, 6, 7, 25, 0);
TimeSpan delta = end - start;

上面的代码声明了两个 DateTime 值,使用构造函数传递年、月、日、小时、分钟和秒。然后,使用减号运算符,我们计算两个值之间的差异,并将其分配给一个新的 TimeSpan 类型变量。

TimeSpan 对象具有几个属性,使您能够检索其值的部分,如 TotalMinutesTotalHoursTotalSeconds 等。

您还可以使用其静态工厂方法创建 TimeSpan 值。例如,如果您需要表示 50 分钟的持续时间,就是这样做的

var duration = TimeSpan.FromMinutes(50);

C 中时间的实际应用

接下来,我们将介绍一些 C# 时间相关编程的实际应用。

显示当前日期和/或时间

许多程序可能需要在它们的UI上显示当前日期和时间。正如你所看到的,DateTime.Now属性在获取值时非常有用。在格式化方面,你可以使用许多变体的ToString()来根据你的需求格式化值。你还有更多特定的方法可供选择,例如ToLongTimeString()ToLongDateString()ToShortDateString()ToShortTimeString()

记录“历史”数据

每当你需要存储事件的时间和日期时,你不应该仅仅使用DateTime.Now来获取时刻。这是因为此属性返回一个值,其Kind属性设置为Local。这意味着该值仅限于生成该值的计算机,而且完全没有时区的概念。在这些情况下,正确的做法是将值保存为UTC,并且仅在显示时将其转换为本地时间。

要获取当前的UTC日期和时间,只需使用DateTime.UtcNow属性

var utcNow = DateTime.UtcNow;

另一种选择是使用不同的类型:而不是使用DateTime,你可以利用DateTimeOffset:

DateTimeOffset localWithOffset = DateTimeOffset.Now;

DateTimeOffset类型包含常规的本地日期,但它还存储了相对于UTC的偏移量。这种方法的好处是保留了本地时间,便于可视化,并在需要时将其转换为通用时间(UTC)。

定义过期日期

在商业中,一个常见的场景是需要定义过期日期:试用期、合同或其它法律条款的结束日期,个人访问令牌的过期日期等等。

通过使用DateTimeAddDays()方法及其配套方法可以轻松地得到这些日期

var today = DateTime.Today;
DateTime tenDaysLater = today.AddDays(10);
DateTime twoMonthsLater = today.AddMonths(2);
DateTime nextYear = today.AddYears(1);

没有Subtract方法。为了从DateTime对象中减去,你只需向Addxxx方法提供负值。

验证或解析文件中的DateTime值

另一个常见的场景是解析存储在文本文件中(例如CSV文件)的日期和时间。由于无法保证这些值实际上是有效的,请确保以健壮的方式编写你的代码。以下代码从CSV文件中的一行中提取并解析日期。代码假设日期位于第二列

void ParseLine(string line)
{
    string[] parts = line.Split(',');
    if (parts.Length < 3)
        throw new InvalidOperationException("File with wrong data!");

    string dateCandidate = parts[1];
    if (!DateTime.TryParse(dateCandidate, out DateTime date))
    {
        throw new InvalidOperationException("Invalid date!");
    }

    // do something useful with date
}

正如你所看到的,没有向方法提供日期格式。如果你在自己的代码上尝试此代码,请确保日期是ISO-8601格式,这样它就会工作。其他格式可能根据你的系统文化可能工作或不工作。

总结

时间处理是编程中的一个巨大主题。它令人着迷、复杂,充满了出错和出现错误的机会。本文对这一主题进行了温和的介绍。你学习了C#中的时间处理是如何工作的,你应该使用的主要类型是什么,甚至还有一些实际场景。

然而,这仅仅是冰山一角。在单篇博客文章的范围内,我无法涵盖这个主题的所有内容。因此,以下是一些你应该自行研究的项目

  • 了解更多关于不同类型的信息——也就是说,一个DateTime可以假设的不同可能的值及其Kind属性,以及它们对你的代码的影响
  • 了解更多关于 TimeZoneInfo 类以及如何处理需要处理 时区 的代码。
  • 研究如何安排未来事件以及夏令时如何给表格带来许多复杂性。

感谢阅读,下次再见。

本文由 Carlos Schults 撰写。 Carlos 是一位咨询和软件工程师,拥有桌面、网页和移动开发的经验。虽然他的主要语言是 C#,但他对多种语言和平台都有所了解。他的主要兴趣包括自动化测试、版本控制和代码质量。