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

我想获取给定date所在月份的第一天和最后一天。date来自UI字段中的值。

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

var maxDay = dtpAttendance.MaxDate.Day; 

但我试图从一个DateTime对象。 所以如果我有这个…

 DateTime dt = DateTime.today; 

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

DateTime结构只存储一个值,而不是值的范围。 MinValueMaxValue是静态字段,它们为DateTime结构的实例保存可能值的范围。 这些字段是静态的,并且不涉及DateTime特定实例。 它们与DateTimetypes本身有关。

推荐阅读: 静态(C#参考)

更新:获取月份范围:

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

这更多的是对@Sergey和@ Steffen的回答。 在过去我自己写了类似的代码,我决定检查什么是最高性能的,同时记住清晰度也很重要。

结果

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

 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#编程模式下)来打开编译器优化来运行testing。 为了清晰和方便,以下是testing代码作为扩展方法的因素:

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

分析

我对这些结果中的一些感到惊讶。

尽pipe在testing的大部分运行中, FirstDayOfMonth_NewMethodFirstDayOfMonth_NewMethod略快。 不过,我认为后者有一个更清晰的意图,所以我有一个偏好。

LastDayOfMonth_AddMethod是一个明显的输家对LastDayOfMonth_AddMethodWithDaysInMonthLastDayOfMonth_NewMethodLastDayOfMonth_NewMethodWithReuseOfExtMethod 。 在最快的三个之间没有太多的内容,所以这取决于你的个人喜好。 我select了LastDayOfMonth_NewMethodWithReuseOfExtMethod的清晰度, LastDayOfMonth_NewMethodWithReuseOfExtMethod用了另一个有用的扩展方法。 恕我直言,其意图更清晰,我愿意接受小的性能成本。

LastDayOfMonth_SpecialCase假定您在特殊情况下提供了本月的第一个月份,您可能已经计算了该date,并使用DateTime.DaysInMonth的add方法获取结果。 如你所料,这比其他版本更快,但是除非你急需速度,否则在你的武器库中看不到这种特殊情况。

结论

这是一个扩展方法类与我的select,并与@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()); } } 

如果你有这么多,谢谢你的时间! 它很有趣:¬)。 如果您对这些algorithm有任何其他build议,请发表评论。

使用.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)); 
 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)); 

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

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

Last day of month ”实际上是“ First day of *next* month, minus 1 ”。 所以这里是我使用的,不需要“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)的原因是因为通常您需要这些date函数来报告某个date时间,并且当您为一段时间生成报告时,“结束date”实际上应该是像Oct 31 2015 23:59:59这样你的报告正常工作 – 包括从最后一天的所有数据。

也就是说,你实际上得到了这个月的“最后一刻 ”。 不是最后一天。

好的,我现在要闭嘴了。

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

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

这样保留了DateTime实例的原始types。

如果你只关心date

 var firstDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind); var lastDay = new DateTime(date.Year, date.Month + 1, 1, 0, 0, 0, date.Kind).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, 1, date.Hour, date.Minute, date.Second, date.Kind).AddDays(-1); 

试试这个:

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

对于波斯文化

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

简单的方法来做到这一点

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