it-swarm.com.ru

Получение первого и последнего дня месяца с использованием заданного объекта DateTime

Я хочу получить первый и последний день месяца, в котором находится данная дата. Дата берется из значения в поле пользовательского интерфейса.

Если бы я использовал таймер, я мог бы сказать,

var maxDay = dtpAttendance.MaxDate.Day;

Но я пытаюсь получить его из объекта DateTime. Так что, если у меня есть это ...

DateTime dt = DateTime.today;

Как получить первый и последний день месяца от dt?

149
CAD

DateTime структура хранит только одно значение, а не диапазон значений. MinValue и MaxValue являются статическими полями, которые содержат диапазон возможных значений для экземпляров структуры DateTime. Эти поля являются статическими и не относятся к конкретному экземпляру DateTime. Они относятся к самому типу DateTime.

Рекомендуемое чтение: статическое (C # Reference)

ОБНОВЛЕНИЕ: Получение месячного диапазона:

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

Это более длинный комментарий к ответам @Sergey и @ Steffen. Написав подобный код в прошлом, я решил проверить, что было наиболее performancemant , помня, что ясность также важна.

Результат

Вот пример результата теста для 10 миллионов итераций:

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_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethod и LastDayOfMonth_NewMethodWithReuseOfExtMethod. Между тремя самыми быстрыми нет ничего особенного, и поэтому все зависит от ваших личных предпочтений. Я выбрал ясность LastDayOfMonth_NewMethodWithReuseOfExtMethod с его повторным использованием другого полезного метода расширения. ИМХО, его цель более ясна, и я готов принять небольшую стоимость производительности.

LastDayOfMonth_SpecialCase предполагает, что вы вводите первое число месяца в особом случае, когда вы, возможно, уже вычислили эту дату, и использует метод add с DateTime.DaysInMonth для получения результата. Как и следовало ожидать, это быстрее, чем в других версиях, но если вам не нужна острая потребность в скорости, я не вижу смысла в том, чтобы иметь этот особый случай в вашем арсенале.

Заключение

Вот класс метода расширения с моим выбором и в общем согласии с @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());
    }
}

Если вы зашли так далеко, спасибо за время! Это было весело: ¬). Пожалуйста, прокомментируйте, если у вас есть другие предложения для этих алгоритмов.

71
WooWaaBob

Получение диапазона месяцев с помощью .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));
12
Steffen Mangold

«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, поэтому ваш отчет работает правильно - включая все данные за последний день месяца.

То есть вы на самом деле получаете «последний момент месяца» здесь. Не последний день.

Хорошо, я сейчас заткнусь.

4
jazzcat
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));
4
sphaze

Здесь вы можете добавить один месяц для первого дня текущего месяца, чем удалить 1 день с этого дня.

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

Если вы заботитесь только о дате 

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
Vitaly

Принятый ответ здесь не учитывает тип экземпляра 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.

1
Marko

Я использовал это в своем сценарии (работает для меня), но мне нужна была полная дата без необходимости ее обрезки до даты и времени.

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

Для персидской культуры 

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);
0
Mohammad Daliri

Попробуй это:

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