首页 文章

使用给定的DateTime对象获取一个月的第一天和最后一天

提问于
浏览
143

我希望获得给定日期所在的月份的第一天和最后一天 . 日期来自UI字段中的值 .

如果我使用时间选择器,我可以说

var maxDay = dtpAttendance.MaxDate.Day;

但我正试图从DateTime对象中获取它 . 所以,如果我有这个......

DateTime dt = DateTime.today;

如何从 dt 获得该月的第一天和最后一天?

12 回答

  • 0

    这是对@Sergey和@Steffen的答案的长篇评论 . 在过去我自己编写了类似的代码后,我决定检查最重要的是什么,同时记住清晰度也很重要 .

    结果

    以下是1000万次迭代的示例测试运行结果:

    2257 ms for FirstDayOfMonth_AddMethod()
    2406 ms for FirstDayOfMonth_NewMethod()
    6342 ms for LastDayOfMonth_AddMethod()
    4037 ms for LastDayOfMonth_AddMethodWithDaysInMonth()
    4160 ms for LastDayOfMonth_NewMethod()
    4212 ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()
    2491 ms for LastDayOfMonth_SpecialCase()
    

    代码

    我使用LINQPad 4(在C#程序模式下)在打开编译器优化的情况下运行测试 . 为了清晰和方便,以下是经过测试的代码作为扩展方法的因素:

    public static class DateTimeDayOfMonthExtensions
    {
        public static DateTime FirstDayOfMonth_AddMethod(this DateTime value)
        {
            return value.Date.AddDays(1 - value.Day);
        }
    
        public static DateTime FirstDayOfMonth_NewMethod(this DateTime value)
        {
            return new DateTime(value.Year, value.Month, 1);
        }
    
        public static DateTime LastDayOfMonth_AddMethod(this DateTime value)
        {
            return value.FirstDayOfMonth_AddMethod().AddMonths(1).AddDays(-1);
        }
    
        public static DateTime LastDayOfMonth_AddMethodWithDaysInMonth(this DateTime value)
        {
            return value.Date.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - value.Day);
        }
    
        public static DateTime LastDayOfMonth_SpecialCase(this DateTime value)
        {
            return value.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - 1);
        }
    
        public static int DaysInMonth(this DateTime value)
        {
            return DateTime.DaysInMonth(value.Year, value.Month);
        }
    
        public static DateTime LastDayOfMonth_NewMethod(this DateTime value)
        {
            return new DateTime(value.Year, value.Month, DateTime.DaysInMonth(value.Year, value.Month));
        }
    
        public static DateTime LastDayOfMonth_NewMethodWithReuseOfExtMethod(this DateTime value)
        {
            return new DateTime(value.Year, value.Month, value.DaysInMonth());
        }
    }
    
    void Main()
    {
        Random rnd = new Random();
        DateTime[] sampleData = new DateTime[10000000];
    
        for(int i = 0; i < sampleData.Length; i++) {
            sampleData[i] = new DateTime(1970, 1, 1).AddDays(rnd.Next(0, 365 * 50));
        }
    
        GC.Collect();
        System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
        for(int i = 0; i < sampleData.Length; i++) {
            DateTime test = sampleData[i].FirstDayOfMonth_AddMethod();
        }
        string.Format("{0} ms for FirstDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
    
        GC.Collect();
        sw.Restart();
        for(int i = 0; i < sampleData.Length; i++) {
            DateTime test = sampleData[i].FirstDayOfMonth_NewMethod();
        }
        string.Format("{0} ms for FirstDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
    
        GC.Collect();
        sw.Restart();
        for(int i = 0; i < sampleData.Length; i++) {
            DateTime test = sampleData[i].LastDayOfMonth_AddMethod();
        }
        string.Format("{0} ms for LastDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
    
        GC.Collect();
        sw.Restart();
        for(int i = 0; i < sampleData.Length; i++) {
            DateTime test = sampleData[i].LastDayOfMonth_AddMethodWithDaysInMonth();
        }
        string.Format("{0} ms for LastDayOfMonth_AddMethodWithDaysInMonth()", sw.ElapsedMilliseconds).Dump();
    
        GC.Collect();
        sw.Restart();
        for(int i = 0; i < sampleData.Length; i++) {
            DateTime test = sampleData[i].LastDayOfMonth_NewMethod();
        }
        string.Format("{0} ms for LastDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
    
        GC.Collect();
        sw.Restart();
        for(int i = 0; i < sampleData.Length; i++) {
            DateTime test = sampleData[i].LastDayOfMonth_NewMethodWithReuseOfExtMethod();
        }
        string.Format("{0} ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()", sw.ElapsedMilliseconds).Dump();
    
        for(int i = 0; i < sampleData.Length; i++) {
            sampleData[i] = sampleData[i].FirstDayOfMonth_AddMethod();
        }
    
        GC.Collect();
        sw.Restart();
        for(int i = 0; i < sampleData.Length; i++) {
            DateTime test = sampleData[i].LastDayOfMonth_SpecialCase();
        }
        string.Format("{0} ms for LastDayOfMonth_SpecialCase()", sw.ElapsedMilliseconds).Dump();
    
    }
    

    分析

    我对其中一些结果感到惊讶 .

    虽然其中没有多少 FirstDayOfMonth_AddMethod 在大多数测试中都略快于 FirstDayOfMonth_NewMethod . 但是,我认为后者有一个更清晰的意图,所以我更喜欢这个 .

    LastDayOfMonth_AddMethodLastDayOfMonth_AddMethodWithDaysInMonthLastDayOfMonth_NewMethodLastDayOfMonth_NewMethodWithReuseOfExtMethod 明显失败 . 在最快的三个之间没有任何内容,因此它取决于您的个人偏好 . 我选择了 LastDayOfMonth_NewMethodWithReuseOfExtMethod 的清晰度,并重用了另一种有用的扩展方法 . 恕我直言,其意图更清晰,我愿意接受小的性能成本 .

    LastDayOfMonth_SpecialCase 假设您在特殊情况下提供了本月的第一个月,您可能已经计算了该日期,并使用带有 DateTime.DaysInMonth 的add方法来获取结果 . 这比其他版本更快,正如您所期望的那样,但除非您迫切需要速度,否则我不认为在您的武器库中有这种特殊情况 .

    结论

    这是一个扩展方法类,我的选择和@Steffen的一般协议我相信:

    public static class DateTimeDayOfMonthExtensions
    {
        public static DateTime FirstDayOfMonth(this DateTime value)
        {
            return new DateTime(value.Year, value.Month, 1);
        }
    
        public static int DaysInMonth(this DateTime value)
        {
            return DateTime.DaysInMonth(value.Year, value.Month);
        }
    
        public static DateTime LastDayOfMonth(this DateTime value)
        {
            return new DateTime(value.Year, value.Month, value.DaysInMonth());
        }
    }
    

    如果你有这个目的,谢谢你的时间!很有趣:¬) . 如果您对这些算法有任何其他建议,请发表评论 .

  • 67
    DateTime dCalcDate = DateTime.Now;
    dtpFromEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, 1);
    dptToEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, DateTime.DaysInMonth(dCalcDate.Year, dCalcDate.Month));
    
  • -1

    这里接受的答案没有考虑DateTime实例的种类 . 例如,如果您的原始DateTime实例是UTC种类,那么通过创建一个新的DateTime实例,您将创建一个Unknown Kind实例,然后根据服务器设置将其视为本地时间 . 因此,获得该月的第一个和最后一个日期的更合适的方法是:

    var now = DateTime.UtcNow;
    var first = now.Date.AddDays(-(now.Date.Day - 1));
    var last = first.AddMonths(1).AddTicks(-1);
    

    这样就保留了原始种类的DateTime实例 .

  • 12

    使用.Net API获取月份范围(只是另一种方式):

    DateTime date = ...
    var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
    var lastDayOfMonth = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
    
  • 360

    简单的方法

    Begin = new DateTime(DateTime.Now.Year, DateTime.Now.Month,1).ToShortDateString();
    End = new DataFim.Text = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)).ToShortDateString();
    
  • 1

    如果你只关心日期

    var firstDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind);
    var lastDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind).AddMonths(1).AddDays(-1);
    

    如果你想保留时间

    var firstDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind);
    var lastDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind).AddMonths(1).AddDays(-1);
    
  • 2

    DateTime结构只存储一个值,而不存储值范围 . MinValueMaxValue 是静态字段,其中包含 DateTime 结构实例的可能值范围 . 这些字段是静态的,与 DateTime 的特定实例无关 . 它们与 DateTime 类型本身有关 .

    推荐阅读:static (C# Reference)

    更新:获得月份范围:

    DateTime date = ...
    var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
    var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
    
  • 4

    试试这个:

    string strDate = DateTime.Now.ToString("MM/01/yyyy");
    
  • 3

    Last day of month " is actually " First day of *next* month, minus 1 ". So here's what I use, no need for " DaysInMonth”方法:

    public static DateTime FirstDayOfMonth(this DateTime value)
    {
        return new DateTime(value.Year, value.Month, 1);
    }
    
    public static DateTime LastDayOfMonth(this DateTime value)
    {
        return value.FirstDayOfMonth()
            .AddMonths(1)
            .AddMinutes(-1);
    }
    

    注意:我在这里使用 AddMinutes(-1) ,而不是 AddDays(-1) 的原因是因为通常您需要这些日期函数来报告某个日期时段,并且当您构建一段时间的报表时,"end date"实际上应该是 Oct 31 2015 23:59:59 ,以便您的报表正常工作 - 包括每月最后一天的所有数据 .

    即你真的得到了“这个月的最后一刻” . 不是最后一天 .

    好的,我现在要闭嘴了 .

  • -2

    我在我的脚本中使用了这个(适用于我),但是我需要一个完整的日期,而不需要将它修剪到只有日期和没有时间 .

    public DateTime GetLastDayOfTheMonth()
    {
        int daysFromNow = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month) - (int)DateTime.Now.Day;
        return DateTime.Now.AddDays(daysFromNow);
    }
    
  • 3

    在这里,您可以为当月的第一天添加一个月,而不是从当天删除1天 .

    DateTime now = DateTime.Now;
    var startDate = new DateTime(now.Year, now.Month, 1);
    var endDate = startDate.AddMonths(1).AddDays(-1);
    
  • 1

    对于波斯文化

    PersianCalendar pc = new PersianCalendar();            
    
    var today = pc.GetDayOfMonth(DateTime.Now);
    var firstDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddDays(-(today-1)));
    var lastDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddMonths(1).AddDays(-today));            
    Console.WriteLine("First day "+ firstDayOfMonth);
    Console.WriteLine("Last day " + lastDayOfMonth);
    

相关问题