只有在C#中的datetypes – 为什么没有datetypes?

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

这个问题的标准方法是什么? 当然,我不是第一个遇到这个? 为什么在C#中没有Date类?

有没有人有一个很好的实现使用一个结构,也许在DateTime上的一些扩展方法,也许实现一些运算符,如==和<,>?

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

  • Jon Skeet的Noda Time库现在已经相当成熟,并且有一个名为LocalDate的datetypes。 (在这种情况下,本地只意味着某人在本地,而不一定是运行代码的计算机本地)。

  • 一个名为Datetypes是通过corefxlab项目build议添加到.NET Core的。 你可以在System.Time包中find它,还有一个TimeOfDaytypes,以及现有types的几个扩展方法。

我已经研究了这个问题,所以我也分享了这些types的必要性的几个原因:

  1. 在仅有date和午夜时间值之间存在逻辑差异。

    • 不是每个地方的每个时区都有一个午夜。 例如:巴西的春季夏令时转换将时钟从11:59:59移到01:00:00。

    • date时间总是表示一天中的特定时间,而date时间则可以表示一天的开始,一天的结束或一天的整个范围。

  2. 如果不仔细观察时区,将时间附加到date可能会导致date发生变化,因为值会从一个环境传递到另一个环境。 这通常发生在JavaScript( Date对象实际上是date+时间)中,但是也可以很容易地在.NET中发生,或者在JavaScript和.NET之间传递数据时在序列化中发生。

  3. 使用XML或JSON(及其他)序列化DateTime始终包含时间,即使它不重要。 这是非常混乱的,特别是考虑像出生date和纪念日等时间无关的事情。

  4. 在架构上, DateTime是一个DDD 值对象 ,但是它违反了单一责任原则的几种方式:

    • 它被devise为date+时间types,但是通常被用作仅仅date(忽略时间),或者仅用于时间(忽略date)。 (时间TimeSpan也经常用于时间,但这是另一个话题。)

    • 附加到.Kind属性的DateTimeKind值将单个types拆分为三个。 Unspecifiedtypes实际上是结构的原始意图,应该以这种方式使用。 Utctypes将值专门与UTCalignment, Localtypes将该值与环境的本地时区alignment。

      有一个单独的标志类的问题是,每次你消费一个DateTime时间,你应该检查。 .Kind来决定采取什么行为。 框架方法都是这样做的,但其他人往往会忘记。 这是一个真正的SRP违规行为,因为这个types现在有两个不同的理由需要改变(价值和种类)。

    • 其中的两个导致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 !!! 

总之,虽然DateTime 只能用于date,但只有在每个使用它的地方都非常小心地忽略时间的情况下才会这样做,并且也非常小心,不要试图转换UTC和UTC其他时区。

我怀疑没有专门的纯Date类,因为你已经有了可以处理它的Date 。 有Date会导致重复和混乱。

如果您希望标准方法查看DateTime.Date属性,该属性只将DateTime.Date的date部分设置为12:00:00(00:00:00)时间值。

我已经发邮件refsrcfeedback@microsoft.com,这是他们的答案

马科斯,这不是问这样的问题的好地方。 尝试http://stackoverflow.com 简短的答案是,你需要一个模型来表示一个时间点,DateTime这样做,这是实践中最有用的场景 。 人类使用两个概念(date和时间)来标记时间点的事实是任意的,对分离没有用处。

只有在需要解耦的地方,不要仅仅为了盲目地做事而做事。 这样想:你有什么问题可以通过将DateTime分成date和时间来解决? 你会得到什么问题,你现在没有? 提示:如果你看看.NET框架中的DateTime用法: http : //referencesource.microsoft.com/#mscorlib/system/datetime.cs#df6b1eba7461813b#references你会看到大多数是从一个方法返回。 如果我们没有像DateTime这样的单一概念,那么就必须使用参数或元组来返回一对Date和Time。

HTH,Kirill Osenkov

在我的电子邮件中,我怀疑这是否是因为DateTime使用TimeZoneInfo获取机器的时间 – 现在是合适的。 所以我想说这是因为它太耦合了,他们对我这么认为。

当你需要一个简单的date时,我创build了一个简单的Date结构 ,而不用担心时间部分,时区,本地和utc等。

https://github.com/claycephus/csharp-date

为什么? 我们只能推测,并不能帮助解决工程问题。 一个很好的猜测就是DateTime包含了这样一个结构所具有的所有function。

如果真的对你很重要,只需将DateTime包装在你自己的不可变的结构中,它只暴露date(或者查看DateTime.Date属性)。

请允许我推测:也许这是因为,直到SQL Server 2008在SQL中没有Date数据types,所以它会很难将它存储在SQL服务器? 毕竟这是微软产品?

如果你需要运行date比较然后使用

 yourdatetime.Date; 

如果您正在显示到屏幕使用

 yourdatetime.ToShortDateString(); 

谁知道为什么这样。 .NET框架中有很多糟糕的devise决定。 不过,我认为这是相当小的一个。 您始终可以忽略时间部分,因此,即使某些代码确定要使DateTime引用的不仅仅是date,也应该只关注date部分。 或者,您可以创build一个只代表date的新types,并使用DateTime中的函数来完成繁重的工作(计算)。

除了罗伯特的答案,你也有DateTime.ToShortDateString方法。 另外,如果你真的想要一个Date对象,你总是可以使用适配器模式,并包装DateTime对象只暴露你想要的(即月,日,年)。

总是有DateTime.Date属性切断了DateTime.Date的时间部分。 也许你可以在你自己的Date类中封装或包装DateTime。

对于这个问题,我想你应该问安德斯·赫尔斯伯格。

因为要知道date,你必须知道系统时间(包括时间) – 为什么要丢弃这些信息呢?

DateTime有一个Date属性,如果你不关心的时间。

是的,也System.DateTime是封闭的。 我已经看到一些人通过创build自定义类来玩游戏,只是为了获得早期post中提到的string值,比如:

 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(); } } } 

这可能是不必要的,因为你可以很容易地从一个普通的旧的DateTimetypes中提取GetShortTimeString,而不需要新的类

如果使用“date”或“今日”属性从DateTime对象中只获取date部分。

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

然后,只有将时间组件设置为午夜,才能获得date组件。