理解 .NET Framework 中的 DateTime 结构(使用 C#)






4.83/5 (9投票s)
了解 DateTime 结构,并在软件中使用它来显示日期和时间,以及进行日期时间数学运算。
引言
本文帮助您理解 Microsoft 为其 Windows 操作系统提供的 .NET Framework 中的 DateTime
结构是什么,以及如何在您的软件中使用它来显示当前或自定义的日期和时间。
此 struct
字段的声明如下:
public struct DateTime : IComparable, IFormattable,
IConvertible, ISerializable, IComparable<DateTime>, IEquatable<DateTime>
您可以看到声明中的 struct
关键字。这告诉编译器(和开发人员),这不是一个类,而是一个结构。
需要注意的是,DateTime struct
是 System
命名空间的直接子项,因此您只需在 C# 类文件中将其添加到您的项目即可。
using System;
背景
很多时候,开发人员喜欢计算自上周末以来到今天的总天数,或者计算用户在其平台上的年龄等等。在我们的语言中,这被称为“DateTime
数学”,即我们计算直到现在的已过日期和时间,计算秒数等等。在执行此操作时,.NET Framework 会处理我们必须做的许多事情,因此我们可以专注于仅获取结果的逻辑,而不是 DateTime
对象的算法。
在本文中,我将尝试解释如何使用 .NET Framework 中内置的默认值,或者通过使用自定义值并将其作为参数传递给 DateTime
构造函数来创建新的 DateTime
对象。
环境要求
如果您在生产环境中使用 Visual Studio,则可以跳过此部分。此部分仅显示在继续阅读本文的后续部分以构建/运行和测试用于教授基础知识的软件演示代码之前,您需要拥有什么。
首先,您需要从 Microsoft 获取 Visual Studio 的副本。您可以获取免费的 Express 版本,或者获取最适合您的版本。它们都可以为您编译代码!
之后,您就可以启动并运行了。该设置本身将安装所有必需的软件到您的系统,并确保您将要编译的软件获得所需的一切。
注意:如果您的系统上安装的是较旧版本的 .NET Framework,它还会更新您的 .NET Framework 版本。较新版本的 .NET Framework 确保了新的方法可用,以及一些安全改进。
DateTime 结构概述 (API)
本文的这一部分提供了 C#(.NET Framework 的 System
命名空间)中 DateTime struct
的一些概述。我将尝试解释该 struct
的构造函数、方法和属性。
本文不会涵盖其中的每一个,但会涵盖基础知识以及您可以使用它们做什么。我将尝试解释并引用 MSDN 库中关于 DateTime struct
或对象(或参数)所属类的每个文档。
DateTime 构造函数
这会初始化 DateTime
对象实例并返回给您以便进一步执行。您经常遇到的(以及在此项目中)的示例构造函数如下:
Signature: new DateTime(int year, int month, int date);
DateTime datetime = new DateTime(1995, 08, 29); // August 29th, 1995
但这只是其中一个。System
命名空间提供了 11 个构造函数,您可以根据使用 DateTime
对象的原因来使用它们。例如,您可能还想向代码添加刻度或毫秒。您可以使用这个:
Signature: new DateTime(int year, int month, int date, int hour, int minute, int seconds);
DateTime dateTime = new DateTime(1995, 08, 29, 00, 00, 00); // August 29th, 1995, 12AM
这是第二个构造函数,它也添加了时间,这样您就可以添加时间。还有一些其他函数,您可以进一步添加 Calender
类型等等。但请记住,这只是向对象添加更多属性的简便方法。您甚至可以创建一个单独的 DateTime
对象,然后添加小时、分钟和秒。但这样做更有效率,也是推荐的方式。
构造函数列表可以在这里找到:
DateTime 字段
字段是包含在 class
或 struct
中的对象或值,您可以使用它们来获取 Class
本身的值,而不是对象。它们定义了 Class
或 Struct
(在我们的例子中是 Struct
)本身的属性,并且对于每个对象实例都是通用的。例如,int
可能有很多对象实例,但它们每个都有相同的 MaxValue
字段。
有两个 DateTime
字段,它们是:
public static readonly DateTime MaxValue;
public static readonly DateTime MinValue;
它们是 static
的,因为它们在整个执行过程中和整个生命周期中都不会改变,并且您无需使用 DateTime
构造函数创建新的 DateTime
实例,就可以轻松地像这样访问它们:
DateTime.MaxValue; // returns DateTime and not int or string
它们是只读的,所以您不能在赋值运算符的左侧使用它们。就是这么简单!
有关 DateTime
字段的更多信息,请阅读 http://msdn.microsoft.com/en-us/library/system.datetime_fields(v=vs.110).aspx。
DateTime 方法
与其他所有 class
和 struct
一样,DateTime
也提供了各种方法(函数),属于此 struct
的对象可以执行这些方法。您可以导航到 MSDN 库并搜索所有方法。但我将讨论基本的方法(省略下面代码中讨论的方法,不想让您混淆)。
DateTime
对象的第一种方法是 Add
函数。
dateTime.Add(TimeSpan param1); // returns DateTime
此函数将新的 TimeSpan
(例如,一个小时或一天等)添加到 dateTime
对象并返回结果。您可以使用它来添加天数,并获得从现在到您添加的天数之后的 DateTime
值。还有其他方法,如 AddDays
和 AddHours
等。
IsLeapYear
是一个函数,用于确定当前年份是否为闰年*。这是一个返回 bool
的函数,因此它将返回 true
或 false
。它将如下所示:
dateTime.IsLeapYear(); // returns false for 2014, but true for 2016 or 2012
*闰年是二月份有 29 天的一年。https://en.wikipedia.org/wiki/Leap_year
DateTime
还提供了一种方法,可以将其他类型转换为 DateTime
对象。例如,如果您有一个表示时间和日期的 string
值,则可以将其转换为 DateTime
。您可以使用 Parse
方法来实现此目的。如果传递无效的日期和时间对象,它会抛出错误。它应该是这样的:
Signature: new DateTime.Parse("mm-dd-yyyy hh:mm:ss");
DateTime dateTime = DateTime.Parse("08-29-1995 00:00:00"); // returns DateTime
正如我下面所说,使用 Convert.ToDateTime(string param1) 是从 String 转换为 DateTime 类的一种更好、更简单的方法。仅在必要时使用此方法!
您可以使用 Subtract
方法从 DateTime
对象中减去 TimeSpan
。它只是 Add
函数的相反操作。
ToLongString
和类似函数(下面代码中使用了三个)仅用于格式化 DateTime
对象,并将其显示为人(用户)友好的版本,而不是计算机友好的版本。您不必担心它,它只是一个花哨的编写器函数。
像每个 class
或 struct
一样,也有一个 ToString
函数。但这个函数还有一些额外功能。如果您传递一些参数,它可以使您的 DateTime
对象风格化。例如,在我的代码中,我传递了一个简单的 string
来将我的 DateTime
对象转换为风格化的 string
并显示结果。
// create a new instance
DateTime dateTime = DateTime.Now;
// convert it to the string, but with parameter
dateTime.ToString("MMMM dd, yyyy hh:mm s's'"); // August 29th, 1995 12:00 00s AM
抱歉,我迫不及待地等待我的生日,所以我使用了 8 月 29 日。
您可以使用许多其他字符在屏幕上获得结果。字符列表可以从 MSDN 获取。
还有许多其他函数可以用来缩短编码时间。虽然您自己也可以做到,但使用这些函数是一种更有效的编码方式,因为 .NET Framework 开发者编写了大量代码来改进我们的软件并缩短我们的开发过程。
有关更多函数,请参阅 http://msdn.microsoft.com/en-us/library/system.datetime_methods(v=vs.110).aspx。
DateTime 属性
这些是对象(而不是 class
或 struct
本身)的属性。每个类都可以有不同的属性,它们取决于对象实例本身,而不是 class
或 struct
。
DateTime
具有非常基本的属性,可以帮助您无需查看日历即可进行 DateTime
数学运算。但它们的设计是为了让您只需写一行代码即可开始。
DateTime
属性都是 non-static
的,除了三个属性是 static
的。
DateTime.Now;
DateTime.Today;
DateTime.UtcNow;
其他所有属性都需要您至少有一个实例才能工作,因为它们依赖于创建的实例。它们是 DateTime
对象的 Day
、DayOfWeek
、Year
等属性。例如:
DateTime dateTime = DateTime.Now; // static
dateTime.Year; // non-static and returns 2014 (int)
还有许多其他属性,它们仅对当前实例有效,并为您提供日期、时间、年份和星期值等。
有关更多信息,请参阅 http://msdn.microsoft.com/en-us/library/System.DateTime_properties(v=vs.110).aspx。
DateTime 运算符
实际上,当 .NET Framework 开发者构建 DateTime struct
时,他们知道 DateTime
有一些不寻常之处需要处理。因为将 1 加到 8 月 1 日没有意义。但是将一天加到 8 月 1 日就有意义了。因此,他们采用了运算符重载的方法,改变了运算符实际使用的方式。
您无需深入了解和学习它,它是直观的,您可以理解当我这样做时可能会发生什么:
dateTime + dateTime1
这会将 dateTime1
对象添加到 dateTime
中,但以 DateTime
的数学方式。
他们只是改变了您计算日期或创建逻辑以检查票据是否有效直到今天的方式,并改变了您在整数对象中使用减法运算符的方式。这一部分不适合我们。 .NET Framework 已经做了足够多的工作,以确保我们只使用简单的数学运算符,并且 DateTime
类会按我们希望的方式对它们进行操作。
有关更多信息,请阅读 http://msdn.microsoft.com/en-us/library/ff986512(v=vs.110).aspx。
下载项目(...并运行它)
您可以从本文顶部的链接下载项目。之后,您需要将其粘贴到您的“Documents\Visual Studio 2013\Projects\”文件夹中,然后运行 Solution 文件。Visual Studio 会自动打开,然后您可以选择构建项目并进行测试,或者继续编辑并使其变得更好。
项目代码和详细信息
此项目是为那些对 DateTime
对象及其操作感到困惑的初学者而构建的。这是一个纯粹的基础概念教程,所以不要认为它可以解决什么高深的问题。我将在下面解释的项目足够您对 DateTime
有基本了解,甚至不需要下载源代码进行测试,但如果您想这样做,请随时下载源代码。
我将解释软件背后的 C# 逻辑,并保持 XAML 代码不变。
在代码中使用 DateTime
您可以在软件的代码中以多种方式使用 DateTime
结构。您可以让编译器使用当前正在执行程序的系统上的当前日期和时间生成此结构的新实例,也可以从用户(或您自己)获取自定义值,然后将其传递给 DateTime
构造函数*,然后将该值显示在屏幕上。
*构造函数:每当创建一个类或结构时,都会调用它的构造函数。构造函数会创建一个该结构或类的新实例。
DateTime
与所有其他 struct
和类一样,都有构造函数,并且根据您的需求有 11 个构造函数。您可以使用其中任何一个,它们都会返回 DateTime struct
的新实例。
正如我所说,您可以获取当前的 DateTime
。为此,您可以使用以下代码获取您计算机上的当前 Date
和 Time
:
var date = DateTime.Now; // current time and date
它将返回您当前的日期和时间。对我来说,现在是:“08/14/2014 01:47:10 AM
”。您的会不同。
完成此操作后,您可以对该实例进行 DateTime
数学运算。
开始使用项目
在软件中,您会在类声明下方的代码顶部看到两个全局变量,如下所示:
private string type = "current"; // a conditional value only
private DateTime dateTime; // a DateTime object for the entire class I am working with
这两个变量在整个软件中使用,因此它们被声明在类内部,而不是任何函数内部。如果我将它们声明在任何方法内部,我将不得不再次编写它们,这就违反了编程的 DRY(Don't Repeat Yourself)原则。
在此新方法被调用后,该方法会获取 DateTime
的值,然后对其进行 DateTime
数学运算,然后调用下一个函数并将数据写入用户界面。它看起来是这样的:
public void GetDateTime()
{
if (type == "current")
{
// current date time is required.
dateTime = DateTime.Now;
this.GetDateTimeFormats(dateTime);
}
else
{
try
{
string value = CustomDateTime.Text;
dateTime = Convert.ToDateTime(value);
this.GetDateTimeFormats(dateTime);
}
catch (Exception ex)
{
MessageBox.Show("There was an error converting the string to datetime.
Try the DateTime in this format mm-dd-yyyy hh:mm:ss\n\n..and remember,
no double quotation marks in the value.");
}
}
}
这会获取值并确保用户需要什么类型的日期和时间。如果他想查看当前的日期时间,它会获取您在 if
块中看到的当前值。否则,它会进入 else
块,并尝试要求用户提供自定义值。此方法初始化我们在类中全局拥有的 dateTime
变量。请参阅上面的代码块。
在此块中,我使用了一个 try catch
块,因为如果用户尝试输入一个无效的日期时间 string
格式的值,则 .NET Framework 会抛出 InvalidFormatException
。为了减少 UI 中出现错误异常的机会,我们使用 try catch
块,我也是如此。这将确保我们传递正确有效的日期时间 string
,以便 .NET 知道如何处理它。
我这次使用的是 Convert.ToDateTime(string parameter)
来将 string
转换为 DateTime
对象。这是将 string
转换为 DateTime
最简单的方法。否则,您也可以使用 DateTime.ParseExact
和所有其他方法来从 String
转换为 DateTime
。但既然您是初学者,我建议您使用这种简单的方法,因为您不必处理 .NET 中的区域性等问题。
提示:不要在值中使用双引号,只需以 mm-dd-yyyy hh:mm:ss 的格式提供数据。例如,08:29:1995 00:00:00 将导致 1995 年 8 月 8 日凌晨 12:00:00(我的生日)。
正如您所见,正在调用另一个方法,该方法用于填充软件的 UI 并向用户显示数据。此方法并不复杂,并且包含了填充 UI 的大部分代码。在此方法中,我们使用 DateTime
的一些函数调用来更改它们的显示(长或短类型)以及检查它们的属性(Length
)等。代码块如下:
public void GetDateTimeFormats(DateTime time)
{
// set the UI values from the DateTime provided in the time parameter.
dateTimeLength.Text = time.ToString().Length.ToString() + " characters.";
dateTimeLongString.Text = time.ToLongDateString();
dateTimeLongTimeString.Text = time.ToLongTimeString();
dateTimeShortString.Text = time.ToShortDateString();
dateTimeShortTimeString.Text = time.ToShortTimeString();
if (type == "custom")
{
if (CustomDateTimeFormat.Text != "")
{
dateTimeToString.Text = time.ToString(CustomDateTimeFormat.Text);
}
else
{
dateTimeToString.Text = time.ToString("MMMM dd, yyyy hh:mm ss's'");
}
}
else
{
dateTimeToString.Text = time.ToString("MMMM dd, yyyy hh:mm ss's'");
}
dateTimeShownAs.Text = "DateTime that you're currently working with is: " +
time.ToString();
this.ElapsedTime(time, new DateTime(1995, 8, 29));
}
此代码获取 DateTime
对象的所有数据,然后将其传递给 XAML 中控件所在的位置,以便用户可以看到正在进行的代码。
您会注意到一些函数,如 ToLongDateString()
和 ToShortTimeString()
。我将把这些留给您去探索代码并自行查找,但请记住,这些只是更改 DateTime
对象视图的一些方法,它们会向您返回一个 string
。
在此代码中,使用了关键字 this
,虽然这不属于 DateTime struct
的一部分,但我还是想给您一些关于它的细节。这个“this
”关键字指的是您当前引用的上下文。在此代码中,它指的是我们代码中的 MainWindow
类。
再次调用了一个新方法,现在代码必须转到新方法并执行该方法调用它的操作。顾名思义,此方法获取两个日期之间的经过时间。第一个参数是当前日期,第二个参数是我们要获取经过时间的日期。
它的声明和主体如下:
public void ElapsedTime(DateTime time1, DateTime time2)
{
TimeSpan timeSpan = time1 - time2;
dateTimeElapsedTime.Text = "Hours elapsed are: " + timeSpan.Hours.ToString();
}
此块是所有代码块中最短的,但我故意这样做的,因为我不希望浪费时间去告诉您距离下个星期五还有多少天,因为你们已经知道了。我想做的是教你们一种创建新 DateTime
实例的方法。
当我使用自定义 DateTime
类时,我使用了 Convert
函数,然后将 string
转换为 DateTime
,但这次我使用的是 int
值来创建新实例。正如我上面提到的,DateTime
有 11 个构造函数(如 MSDN 在上面的链接中所述),其中有一个构造函数,您可以传递整数值,.NET 会完成您的工作,并将它们转换为新的 DateTime
实例供您使用。
例如,在我使用的代码中...
new DateTime(1995, 8, 29);
...这会创建一个新的 DateTime
对象实例。您可以看到我正在使用 new
关键字来声明我想要一个新的 DateTime
,但它的值是多少?这就是我正在传递给构造函数的值。我正在使用的构造函数如下:
public DateTime(
int year,
int month,
int day
)
第一个参数是年份,第二个是月份,第三个是日期。您需要确保这些参数的准确性,一个小错误就会导致年份的改变。之后,您可以获取您的 DateTime
对象并像我一样使用它。例如,代码创建了一个新的 datetime
,它引用了 1995 年 8 月 29 日午夜 12 点,也就是我出生的日期。然后代码执行并提供我直到现在经过的时间等等。
使用软件(教程)
如果您愿意,现在就可以使用该软件,看看 DateTime
对象是如何创建的,以及当您传递某种类型的值时,您会得到什么样的显示值。
主页
软件的主页设置为使用 System
日期时间作为 DateTime
对象,并为您提供当前日期时间的详细信息。还调用了一些其他属性和函数,以便您可以看到 DateTime
的不同样式。
这是主页,您可以看到对我来说它使用了当前的日期时间!
自定义 DateTime 页面
您可以通过点击右侧写有“自定义 DateTime 页面”的地方来导航到自定义 DateTime
页面。
系统会要求您输入有效的日期时间值,否则您将收到以下错误消息:
您可以看到我尝试输入了错误的值,软件会提示我输入正确的值以便处理。
有效 DateTime 值(无格式化)
输入一个有效值,您就会得到这个:
上面的视图是默认设置,但这是一个自定义日期时间对象。您可以看到第二个输入框是空的,但代码仍在执行,这是因为软件有一个默认值(我在软件中这样写了,它是默认的,否则 .NET Framework 中不存在提供此值的默认值),即“MMMM dd, yyyy hh:mm:ss's'”。
有效值和屏幕结果(带格式化)
您甚至可以传递自己的格式化 string
并获得所需的 string
。
您可以看到最后一行只写了“August”,因为我只要求编译器提供 DateTime
实例的月份值“MMMM
”。
尝试使用该软件来测试 DateTime struct
中的值。
关注点
实际上,这篇文章是作为一个整体写成的,然后我被迫删除它,并在 Visual Studio 中重写了一个新项目,然后用新的源代码写了一篇新文章,因为我认为 DateTime
是一个类。但 MSDN 说它是一个 struct
,为了不让开发人员混淆,我通过删除所有先前的内容并重新创建它来消除歧义。
所以,我了解到 DateTime
是一个 struct
而不是一个 Class
对象。
我学到的第二件事是,您可以从一个日期减去另一个日期,结果存储在 TimeSpan
对象中,然后该对象可以接受 DateTime
方法并为您提供直到现在的经过的小时和年数。
历史
- 第一篇帖子