仅在C#中的日期类型 - 为什么没有日期类型?

时间:2011-03-15 15:50:34

标签: c# datetime date

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

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

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

14 个答案:

答案 0 :(得分:37)

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

  • 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. 使用XML或JSON(和其他人)序列化DateTime始终包括时间,即使它不重要。这非常令人困惑,特别是考虑到出生日期和周年纪念日等问题,时间无关紧要。

  4. 在架构上,DateTimeDDD value-object,但它在几个方面违反了Single Responsibly Principle

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

    • 附加到DateTimeKind属性的.Kind值将单个类型拆分为三个,Unspecified种类实际上是结构的原始意图,应该使用办法。 Utc种类特定地将值与UTC对齐,Local种类将值与环境的本地时区对齐。

      为kind提供单独的标记的问题是,每次使用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 !!!
      
  5. 总之,虽然DateTime 可以仅用于日期,但只有当每个使用它的地方都非常小心地忽略时间时,它才会这样做,并且也非常小心,不要尝试转换为UTC或其他时区。

答案 1 :(得分:17)

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

如果您想要标准方法,请查看DateTime.Date属性,该属性仅提供DateTime的日期部分,其时间值设置为午夜12:00:00(00:00:00)

答案 2 :(得分:11)

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

  

马科斯,这不是一个提出这些问题的好地方。试试http://stackoverflow.com   简短回答是您需要一个模型来表示某个时间点,而DateTime会这样做,这是实践中最有用的方案。人类使用两个概念(日期和时间)来标记时间点的事实是任意的,对于分离是没有用的。

     

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

     

HTH,   基里尔奥森科夫

在我的电子邮件中,我质疑是否因为DateTime使用TimeZoneInfo来获取机器的时间 - 现在是正确的。所以我说这是因为“业务规则”“过于耦合”,他们向我说明了这一点。

答案 3 :(得分:10)

当你需要一个简单的约会而不用担心时间部分,时区,本地和utc等时,我创建了一个简单的Date struct

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

答案 4 :(得分:5)

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

yourdatetime.Date;

如果您正在显示屏幕,请使用

yourdatetime.ToShortDateString();

答案 5 :(得分:3)

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

如果它对您真的很重要,只需将DateTime包装在您自己的不可变结构中,该结构只显示日期(或查看DateTime.Date属性)。

答案 6 :(得分:3)

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

对于这个问题,为什么,嗯,我想你必须要问Anders Heljsberg。

答案 7 :(得分:3)

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

答案 8 :(得分:2)

谁知道为什么会那样。 .NET框架中有许多糟糕的设计决策。但是,我认为这是一个非常小的问题。你总是可以忽略时间部分,所以即使某些代码决定让DateTime引用的不仅仅是日期,关心的代码也应该只看日期部分。或者,您可以创建一个仅代表日期的新类型,并使用DateTime中的函数来执行繁重的工作(计算)。

答案 9 :(得分:2)

除了罗伯特的回答,您还有 DateTime.ToShortDateString 方法。此外,如果你真的想要一个Date对象,你总是可以使用Adapter模式并将DateTime对象包装成只暴露你想要的东西(即月,日,年)。

答案 10 :(得分:1)

因为要知道日期,你必须知道系统时间(以刻度表示),其中包括时间 - 那么为什么要丢弃这些信息?

DateTime如果您根本不关心时间,则会Date属性。

答案 11 :(得分: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

答案 12 :(得分:1)

int *ptr = func_arg+10;System.DateOnly 类型最近添加到 .NET 6 中,并且在每日构建中可用。

它们包含在 .NET 6 Preview 4 版本中。

https://github.com/dotnet/runtime/issues/49036

它们位于此处的 .NET 源代码中:

I've blogged about them here.

答案 13 :(得分:0)

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

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

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