仅C#中的Date类型-为什么没有Date类型?


106

在我们的C#项目中,我们需要表示一个没有时间的日期。我知道存在DateTime,但是它也包含一天中的某个时间。我想明确指出某些变量和方法参数是基于日期的。因此,我不能使用该DateTime.Date属性

解决此问题的标准方法是什么?我当然不是第一个遇到这个问题的人吗?为什么DateC#中没有课程?

是否有人使用struct以及在DateTime上使用一些扩展方法以及实现一些运算符(例如==和<,>)实现了一个不错的实现?


1
虽然我了解想要明确,清晰的语义,但是会DateTime产生哪些具体问题?
杰夫·斯坦恩

15
1我需要记住删除方法开始时的小时数。2它不能很好地传达信息,它仅适用于日期。这一点很重要,例如,当从Db进行存储和加载时,窄类型就足够了。编程是人们而非计算机的交流
Carlo V. Dango

5
我只是想说缺少日期类是一件大事,而使用DateTime根本没有好处。一旦将“日期”存储为日期时间,就会成为语言环境/时区夏时制问题的人质。丢掉时间部分可以将您的所有日期发送回时钟改变的一天(!)。并且,不同时区的用户在尝试转换日期时间时会看到不同的日期。日期时间可以表示精确的时刻(从某个点到任何点的抖动),但非常不适合表示抽象日期。
TheMathemagician'1

2
后来出现类似的问题 stackoverflow.com/questions/7167710/…,乔恩·斯凯特(Jon Skeet)说应该有一个日期。
goodeye

7
仅日期数据类型为DateTime,而整数数据类型为小数。那些主张我们不需要日期的人,因为您可以只舍弃时间部分,就像说我们不需要整数一样,因为我们可以舍弃小数部分。我们的世界有一个不包含时间的日期概念。3月5日不是3月5日00:00:00。
Vague

Answers:


54

请允许我为这个经典问题添加更新:

  • 乔恩·斯凯特(Jon Skeet)的Noda Time库现在已经相当成熟,并且具有称为的仅日期类型LocalDate。(在这种情况下,本地是指某人的本地,而不一定是运行代码的计算机的本地。)

  • Date通过corefxlab项目,建议将仅日期类型称为.NET Core 。您将在System.Time包中找到它,以及TimeOfDay类型和对现有类型的几种扩展方法。

我已经对这个问题进行了深入的研究,因此,我还将分享几种使用这些类型的必要性的原因:

  1. 仅日期和午夜日期之间存在逻辑上的差异。

    • 并非每个本地日在每个时区都有一个午夜。示例:巴西的春季夏令时过渡将时钟从11:59:59移至01:00:00。

    • 日期时间始终是指一天中的特定时间,而仅日期可能是指一天的开始,一天的结束或一天的整个范围。

  2. 如果未非常仔细地观察时区,则将时间附加到日期可能导致日期更改,因为值是从一个环境传递到另一个环境的。这通常发生在JavaScript中(其Date对象实际上是一个日期和时间),但是也很容易在.NET中发生,或者在JavaScript和.NET之间传递数据时进行序列化。

  3. DateTime使用XML或JSON(及其他)进行序列化将始终包含时间,即使这并不重要。这非常令人困惑,尤其是考虑到出生日期和周年纪念日等与时间无关的事情。

  4. 从体系结构上讲,它DateTimeDDD的 价值对象,但它在以下几种方面违反了“ 单一负责任原则”

    • 它设计为日期+时间类型,但通常仅用作日期(忽略时间)或仅用作日期时间(忽略日期)。(TimeSpan通常也用于一天中的时间,但这是另一个主题。)

    • DateTimeKind附加到.Kind属性的值将单个类型分成三个类型。该Unspecified类型实际上是结构的原始意图,应以这种方式使用。该Utc种对齐专门与UTC值,和Local那种对齐与环境的本地时区的价值。

      带有单独的种类标记的问题在于,每次使用时DateTime都应检查.Kind以确定采取哪种行为。框架方法都可以做到这一点,但是其他方法经常会忘记。这确实是违反SRP的,因为类型现在有两个不同的更改原因(值和种类)。

    • 这两个导致API使用情况会编译,但通常是荒谬的,或者是由副作用引起的奇怪情况。考虑:

      // nonsensical, caused by mixing types
      DateTime dt = DateTime.Today - TimeSpan.FromHours(3);  // when on today??
      
      // strange edge cases, caused by impact of Kind
      var london = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
      var paris = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
      var dt = new DateTime(2016, 3, 27, 2, 0, 0);  // unspecified kind
      var delta = paris.GetUtcOffset(dt) - london.GetUtcOffset(dt);  // side effect!
      Console.WriteLine(delta.TotalHours); // 0, when should be 1 !!!

总而言之,虽然a DateTime 只能用于日期,但只有在每个使用它的地方都非常小心地忽略时间,并且也非常小心不要尝试与UTC或其他时间相互转换时,才应使用a时区。


2
如果只能System.Time.Date在.NET框架中使用:/
RobertJørgensgaardEngdahl

1
您今天就可以使用它,只需订阅corefx myget提要,就可以System.Time像其他任何软件包一样拉入。它还不是“官方”的。
马特·约翰逊·品脱

17

我怀疑没有专用的纯Date类,因为您已经DateTime可以使用它。有Date会导致重复和混乱。

如果要使用标准方法,请查看DateTime.Date属性,该属性仅给出a的日期部分,DateTime其时间值设置为午夜12:00:00(00:00:00)。


59
专用的Date类的一大优点是它不受时区和夏时制的复杂性的影响。
Dimitri C.

3
@DimitriC。我不同意-您可以将DateTime与UTC一起使用,并且不会遇到上述问题,并且即使加上日期时间,即使您只想要日期,仍然可以进行涉及时间的数学运算(即如果我减去20 x 2小时,请给我日期)从今天开始)。
罗伯特·麦克莱恩

@Robert MacLean:感谢您强调使用UTC DateTimes的便利。我做了一些测试,看起来像DateTimeKind.Unspecified行为像UTC关于减法。因此,的确,如果您对正在使用的DateTime的“种类”保持谨慎,一切都会很好。
Dimitri C.

10
必须考虑UTC以及与时区有关的一切只是浪费能量,因为可以通过单独的Date类轻松避免这种情况。而且我没有看到Date和DateTime之间有任何混淆。
maulik13

5
同意C#确实应该具有Date类。时区转换不仅是海底bug的持续来源,而且在处理基于工作日而不是基于时间的事情时也很痛苦。
朱利安·伯奇

12

我已经通过电子邮件发送给refsrcfeedback@microsoft.com,这就是他们的答案

Marcos,这不是问这类问题的好地方。尝试http://stackoverflow.com 简短的答案是,您需要一个模型来表示一个时间点,而DateTime做到了,这是实践中最有用的方案。人类使用两个概念(日期和时间)来标记时间点这一事实是任意的,并且对区分没有用。

仅在需要的地方解耦,不要仅仅为了盲目的做事。这样想:将DateTime分为Date和Time可以解决什么问题?您会遇到哪些现在没有的问题?提示:如果您查看整个.NET框架中的DateTime用法:http : //referencesource.microsoft.com/#mscorlib/system/datetime.cs#df6b1eba7461813b#references 您将看到大多数方法都从该方法返回的。如果没有类似DateTime的概念,则必须使用out参数或元组返回一对Date和Time。

HTH,基里尔·奥森科夫

在我的电子邮件中,我问是否是因为DateTime使用TimeZoneInfo来获取机器的时间-在Now propriety中。所以我要说这是因为“业务规则”太“耦合”了,他们向我承认了这一点。


这篇文章确实提供了对于没有内置日期类的设计决策背后的想法的见解。您向他们发送的问题是什么?我并不是要表示同意上述决定,原因是上述@TheMathemagician列出的原因。
罗伯特·约根斯加德·恩达尔(RobertJørgensgaardEngdahl)

不幸的是,@RobertJørgensgaardEngdahl我已经无法访问该电子邮件帐户。但是我相信我已经问过他们为什么他们在DateTime结构中将时间和日期耦合在一起。并且我认为我同意TheMathemagician的观点,我认为MS采用这种设计方法是因为作为一家跨国公司,它可以满足他们的需求-现在来改变它已经很晚了-而拆分概念却没有。
MVCDS

2
也许MS可以全力以赴,实施一SpaceTime堂课!嘿,根据爱因斯坦的说法,时间和空间紧密相连,所以我们也不需要区分它们,对吗?(!!!!!!!!!!!)我有点新的C#,但我不得不说,这是从VB.NET来一个雷区在哪里,简单地说,dateToday()now,等没有DateTime前缀的垃圾,无关于。(这些分号以及这种区分大小写的方法肯定令人讨厌!现在就开枪吧!)
SteveCinq

2
并且他们自己的SQL Server具有Date类型,结果必须是类型Date-如果它是Date类型,则结果应作为字符串而没有时间。例如,Delphi也将Date作为DateTime,但是typeinfo对于Date和DateTime是不同的。
user2091150

1
基里尔·奥森科夫(Kirill Osenkov)回答了“为什么没有单独的日期和时间类别日期时间类别?”的问题。在实际使Q为“为什么不有单独的日期和时间类?”。我了解,对于日期时间概念的许多使用案例,日期和时间应该耦合到一个类中。但是,至少可能有和日期概念一样有效的用例。当然,时间概念也有很多有效的用例。
汤姆(Tom),


4

如果您需要进行日期比较,请使用

yourdatetime.Date;

如果要显示在屏幕上,请使用

yourdatetime.ToShortDateString();

.Date部分是我想要的。
布伦丹·沃格特

3

请允许我推测:也许是因为直到SQL Server 2008为止SQL中都没有Date数据类型,所以很难将其存储在SQL Server中?毕竟这是Microsoft产品吗?


db datetime与C#datetime不同。db datetime没有时区,因此它们实际上并未引用特定时刻。但是C#确实知道瞬间,并且存储自UTC时代以来的滴答声。
artsrc 2011年

2
讨论是关于专用DATE的,而不是日期时间部分的,所以我不理解您要提出的重点?
Pleun

这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方发表评论。
Barranka 2015年

@Barranka-问题包含“为什么C#中没有Date类?”
STLDev

2

谁知道为什么会这样。.NET框架中有许多错误的设计决策。但是,我认为这是一个很小的问题。您始终可以忽略时间部分,因此,即使某些代码确实决定让DateTime引用的不只是日期,所关心的代码也应该只查看日期部分。另外,您可以创建一个仅表示日期的新类型,并使用DateTime中的函数进行繁重的工作(计算)。


1
我真的不认为这是一个错误的决定,无论您是否只想使用日期。我不会拒绝投票,但这是我的意见。
2011年

我认为我的措词不好。尽管从抽象/优雅的角度来看,拥有两种或三种类型的方法更合适,但实际上,我本身对此并没有多大问题。我的观点确实是,.NET框架中的许多内容可能会让您抓狂,也不值得为此感到沮丧,尤其是考虑到与某些过分的设计决策(通用约束)。
siride

+1是因为它是真的。这是.NET的唯一问题(或最大的问题):-) :-)他们需要添加DATE和TIME类型的SQL Server多少个版本?而且它们更加有用(至少出于完整性方面的考虑)
xanatos 2011年

我还应该补充一点,我认为“一切都始于-100点”是制作可怜的框架的好方法,而这可能是陷入垃圾中的事情之一。
siride

2
我只是被这个问题所困扰,因为其中一部分代码忽略了使用.Date属性,因此无法正确比较。我绝对认为有必要不保存任何时间的Date类型,以避免此类错误
JoelFan 2012年

2

为什么?我们只能推测,它对解决工程问题没有多大帮助。一个很好的猜测是它DateTime包含了这种结构所具有的所有功能。

如果对您确实很重要,则只需包装DateTime您自己的不可变结构即可,该结构仅公开日期(或查看DateTime.Date属性)。


2

除了罗伯特的回答,您还可以使用该DateTime.ToShortDateString方法。另外,如果您确实想要Date对象,则可以始终使用Adapter模式并包装DateTime对象,从而仅暴露所需内容(即月,日,年)。


2

总有一个DateTime.Date属性会切断的时间部分DateTime。也许您可以将DateTime封装或包装在您自己的Date类型中。

关于这个问题,为什么呢,我想您不得不问Anders Heljsberg。


1

因为要知道日期,您必须知道系统时间(以滴答为单位),其中包括时间-那么为什么要丢弃该信息呢?

DateTimeDate如果您根本不在乎时间,则可以拥有财产。


1

是的,System.DateTime也是密封的。我见过一些人通过创建自定义类来玩游戏,以获取前面的文章中提到的时间的字符串值,例如:

class CustomDate
{
    public DateTime Date { get; set; }
    public bool IsTimeOnly { get; private set; }

    public CustomDate(bool isTimeOnly)
    {
        this.IsTimeOnly = isTimeOnly;
    }

    public string GetValue()
    {
        if (IsTimeOnly)
        {
            return Date.ToShortTimeString();
        }

        else
        {
            return Date.ToString();
        }
    }
}

这可能是不必要的,因为您可以轻松地从普通的旧DateTime类型中提取GetShortTimeString而无需新类


0

如果您使用Date或Today属性从DateTime对象中仅获取日期部分。

DateTime today = DateTime.Today;
DateTime yesterday = DateTime.Now.AddDays(-1).Date;

然后,仅将时间部分设置为午夜,您将获得日期部分。


1
这绝对不是我想要的
卡罗五男子

@Carlo V. Dango:我不同意。我认为这正是您想要的。
siride

1
@Carlo V. Dango:这些属性不允许您完成哪些工作?
eph_tagh 2011年

5
这很容易:Date内存占用量可能仅为DateTime的内存占用量的一半(32位而不是64位)。您可以确定您的愚蠢的同事没有在您的日期中更改.AddHours(1),而是从“仅日期”的POV中“保持相同”。如果(由于错误)将DateTime设置为DateTimeKind.Local,并且将时间标准化为UTC,则Date可能会更改(通过使用XmlSerialization以及对JSON的往返处理不好对我来说发生了)...够吗?
xanatos 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.