在 .NET 6 中使用 DATEONLY 和 TIMEONLY
在 即将发布的.NET 6中,引入了两种期待已久的类型作为核心库的一部分。DateOnly和TimeOnly允许开发人员表示 DateTime 的日期或时间部分。这两种新类型是结构体(值类型),可以在您的代码独立处理日期或时间概念时使用。这两种类型都可以在 System 命名空间中找到。使用这些新类型可能与数据库允许表示类似数据的方式很好地保持一致。具体来说,这些类型与 SQL Server 日期和时间数据类型非常吻合。
注意:要访问这些类型,您需要下载并安装 .NET 6 预览版 4[1](或更新版本)和Visual Studio 16.11(当前处于预览版)[2]。
在 .NET 6 中使用 DATEONLY
这些类型对于它们所代表的内容几乎是不言自明的。当我们需要表示没有时间组件的日期时,我们可以使用 DateOnly。例如,也许我们在应用程序中代表某人的出生日期。在这种情况下,我们很少需要使用 DateTime 的时间部分,标准的解决方案是将时间设置为 00:00:00.000。使用 DateOnly,我们可以更明确地说明我们的意图。
我们可以在 DateOnly 上构造一个实例,将年、月和日作为参数传递:
var date = new DateOnly(2020, 04, 20);
这将创建一个表示 2020 年 4 月 20 日的 DateOnly。在内部,DateOnly 结构使用一个整数来跟踪有效范围为 0(映射到 0001 年 1 月 1 日到 3,652,058,映射到 9999 年 12 月 31 日)的日数。
通常,您将开始使用现有的 DateTime 并希望从中创建一个 DateOnly 实例。为此,我们可以调用 FromDateTime 方法:
var currentDate = DateOnly.FromDateTime(DateTime.Now);
与现有的 DateTime 类型一样,我们也可以使用 Parse 将表示日期的字符串解析为其 DateOnly 表示,这可能会引发异常或 TryParse,它返回一个指示成功或失败的布尔值。
if (DateOnly.TryParse("28/09/1984", new CultureInfo("en-GB"), DateTimeStyles.None, out var result))
{Console.WriteLine(result);
}
上面的代码尝试从第一个参数(日期的字符串表示)解析日期。由于不同的国家和地区对日期的解释不同,因此日期的解析可能会受到文化的影响。在此示例中,我明确提供了 en-GB 区域性以确保它使用日/月/年格式从字符串中正确解析。
如果 DateOnly 已成功解析,则将其写入控制台。再次; 文化在这里扮演着重要的角色。在此示例中,正在运行的线程的当前区域性用于确定所使用的格式。根据我的系统配置,我的应用程序线程恰好在 en-GB 下运行,因此格式化的字符串显示为:
28/09/1984
要了解有关解析和格式化的更多信息,您可以查看我最新的 Pluralsight 课程,C# 中的字符串操作:最佳实践[3]。
我们还可以向 DateOnly 实例添加天数、月数或年数,从而产生具有调整日期的新实例。
var newDate = date.AddDays(1).AddMonths(1).AddYears(1);
在 .NET 6 中使用 TIMEONLY
TimeOnly 结构体用于表示与日期无关的时间。例如,想象一下创建一个闹钟应用程序,让用户创建一个重复发生的闹钟。在这种情况下,我们想要存储闹钟应该响起的时间,但日期无关紧要。
TimeOnly 类型有几个构造函数重载。我希望大多数开发人员使用的更常见的允许我们创建一个日期,接受时间的小时和分钟,小时,分钟和秒,或小时,分钟,秒和毫秒。
public TimeOnly(int hour, int minute)
public TimeOnly(int hour, int minute, int second)
public TimeOnly(int hour, int minute, int second, int millisecond)
例如,要表示上午 10:30,我们可以创建以下 TimeOnly 实例。
var startTime = new TimeOnly(10, 30);
小时部分预计将使用 24 小时时钟格式提供,其中 1pm 是 13 小时。
在内部,TimeOnly 存储一个 long,它表示从午夜到定义的时间已经过去的滴答数(100 纳秒间隔)。例如,凌晨 1 点是一天中的 1 小时,因此自午夜 (00:00:00.0000000) 起有 36,000,000,000 个滴答声。尽管我们也可以通过提供刻度作为参数来构造 TimeOnly,但此实现细节对于一般用途而言并非必不可少。
public TimeOnly(long ticks);
在上面定义了开始时间后,让我们使用另一个 TimeOnly 实例定义下午 5 点的结束时间。
var endTime = new TimeOnly(17, 00, 00);
我们现在可以对这些 TimeOnly 实例执行数学运算,例如计算差异。
var diff = endTime - startTime;
此操作的返回类型是 TimeSpan,然后我们可以使用它来写入两次之间的小时数。
Console.WriteLine($"Hours: {diff.TotalHours}");// Output = Hours: 6.5
我们可以执行的另一个检查是确定特定的 TimeOnly 是否在时间窗口内。例如,假设我们要检查当前时间是否在我们已经定义的开始时间和结束时间之间。与 DateOnly 一样,我们可以使用 FromDateTime 静态方法将现有 DateTime 转换为 TimeOnly。
var currentTime = TimeOnly.FromDateTime(DateTime.Now);var isBetween = currentTime.IsBetween(startTime, endTime);Console.WriteLine($"Current time {(isBetween ? "is" : "is not")} between start and end");
上面的代码现在将写入控制台当前时间是否介于 10:30(上午 10:30)和 17:00(下午 5 点)之间。
IsBetween 方法接受正常范围(例如我们在前面的示例中使用的范围)以及跨越午夜的范围(例如 22:00-02:00)。
var startTime = new TimeOnly(22, 00);var endTime = new TimeOnly(02, 00);var now = new TimeOnly(23, 25); var isBetween = now.IsBetween(startTime, endTime);Console.WriteLine($"Current time {(isBetween ? "is" : "is not")} between start and end"); // Output = Current time is between start and end
TimeOnly 还包括使用循环时钟比较时间的运算符。
var startTime = new TimeOnly(08, 00);var endTime = new TimeOnly(09, 00); Console.WriteLine($"{startTime < endTime}");// Output = True
此代码检查上午 8 点是否早于上午 9 点,这显然是!
概括
我们对这两种新类型的早期研究到此结束,这两种类型已经在 .NET 6 预览版 4 中出现。我觉得值得强调这些类型的存在,因为当我们习惯于默认为 DateTime/DateTimeOffset 时,这些更改很容易错过在过去。如果您的数据需要独立表示日期或时间,那么 DateOnly 和 TimeOnly 值得考虑用于面向 .NET 6 的新应用程序。
References
[1]
安装 .NET 6 预览版 4: https://dotnet.microsoft.com/download/dotnet/6.0?WT.mc_id=DT-MVP-5002866[2]
Visual Studio 16.11(当前处于预览版): https://visualstudio.microsoft.com/vs/preview/?WT.mc_id=DT-MVP-5002866[3]
C# 中的字符串操作:最佳实践: https://www.stevejgordon.co.uk/pluralsight.pxf.io/EaEV1P