繁体   English   中英

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

[英]Getting the first and last day of a month, using a given DateTime object

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

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

var maxDay = dtpAttendance.MaxDate.Day;

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

DateTime dt = DateTime.today;

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

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

建议阅读:静态(C# 参考)

更新:获取月份范围:

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

这是对@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_AddMethod明显LastDayOfMonth_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());
    }
}

如果你已经走到这一步,谢谢你的时间! 它很有趣:¬)。 如果您对这些算法有任何其他建议,请发表评论。

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

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)的原因是因为通常您需要这些日期函数来报告某个日期期间,并且当您为某个期间构建报告时,“结束日期”实际上应该类似于Oct 31 2015 23:59:59这样您的报告可以正常工作 - 包括一个月最后一天的所有数据。

也就是说,您实际上在这里获得了“本月的最后一刻”。 不是最后一天。

好的,我现在要闭嘴了。

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 now = DateTime.Now;
var startDate = new DateTime(now.Year, now.Month, 1);
var endDate = startDate.AddMonths(1).AddDays(-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);

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

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

这样,DateTime 实例的原始 Kind 得以保留。

试试这个:

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

我在我的脚本中使用了它(对我有用),但我需要一个完整的日期,而无需将其修剪为仅日期而不是时间。

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

你能行的

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

试试这个。 它基本上计算DateTime.Now上已经过去的天数,然后从中减去一个并使用新值来查找当月的第一天。 从那里它使用DateTime并使用.AddMonths(-1)来获取上个月的第一天。

获得上个月的最后一天做基本上是同样的事情,除了它在一个月增加了一到天数减去该值DateTime.Now.AddDays ,给你上月的最后一天。

int NumberofDays = DateTime.Now.Day;
int FirstDay = NumberofDays - 1;
int LastDay = NumberofDays + 1;
DateTime FirstofThisMonth = DateTime.Now.AddDays(-FirstDay);
DateTime LastDayOfLastMonth = DateTime.Now.AddDays(-LastDay);
DateTime CheckLastMonth = FirstofThisMonth.AddMonths(-1);

你可以试试这个来获取当前月份的第一天;

DateTime.Now.AddDays(-(DateTime.Now.Day-1))

并为其赋值。

像这样:

dateEndEdit.EditValue = DateTime.Now;
dateStartEdit.EditValue = DateTime.Now.AddDays(-(DateTime.Now.Day-1));

创建 DateTime 类的实例

DateTime dateTime = DateTime.Now;

如果你想得到这个月的最后一天,你可以这样做

int lastDayOfMonth = DateTime.DaysInMonth(caducidadPuntos.Year, caducidadPuntos.Month);

如果你想得到一个月的第一天,你可以这样做

DateTime firstDayMonth = new DateTime(dateTime.Year, dateTime.Month, 1);

我们要求能够获取给定日期月份的开始和结束时间,包括时间在内。 我们最终使用了上述解决方案,非常感谢这里的每个人,并将其组合到一个 util 类中,以便能够获得给定月份和年份数字组合的开始和结束直到最后一毫秒。 包括我们在帮助其他人的情况下向前推进的内容。

实用程序:

    public class DateUtil
    {
        public static (DateTime startOfMonth, DateTime endOfMonth) GetStartAndEndOfMonth(int month, int year)
        {
            DateTime startOfMonth = GetStartOfMonth(month, year);
            DateTime endOfMonth = GetEndOfMonth(month, year);
            return (startOfMonth, endOfMonth);
        }

        public static DateTime GetStartOfMonth(int month, int year)
        {
            return new DateTime(year, month, 1).Date;
        }

        public static DateTime GetEndOfMonth(int month, int year)
        {
            return new DateTime(year, month, 1).Date.AddMonths(1).AddMilliseconds(-1);
        }
    }

用法:

(DateTime startOfMonth, DateTime endOfMonth) = DateUtil.GetStartAndEndOfMonth(2, 2021); // February, 2021

简单的方法来做到这一点

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();
DateTime dCalcDate = DateTime.Now;
var startDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), 1);
var endDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), DateTime.DaysInMonth((Convert.ToInt32(Year)), Convert.ToInt32(Month)));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM