Belirli bir DateTime nesnesini kullanarak ayın ilk ve son gününü alma


198

Belirli bir tarihin bulunduğu ayın ilk gününü ve son gününü almak istiyorum. Tarih, kullanıcı arayüzü alanındaki bir değerden geliyor.

Eğer bir zaman seçici kullanıyorsam diyebilirim

var maxDay = dtpAttendance.MaxDate.Day;

Ama ben bir DateTime nesnesinden almaya çalışıyorum. Eğer buna sahipsem ...

DateTime dt = DateTime.today;

Ayın ilk günü ve son günü nasıl alınır dt?


Ne istediğini belli değil. _DateDeğişkende saklanan tek bir değer vardır . Bu değerden ne "min ve maks" almaya çalışıyorsunuz?
David

aşağı iniyor çünkü insanlar neden böyle bir düşünce yapmak isteyeceğinizi ve böyle bir şeyi nerede kullanacağınızı merak ediyorlar. Burada ilk
Mo Patel

Ne yapmak istediğinizi sormak daha iyidir ? böyle değil Nasıl yapmak istiyorsun? başka kullanımlar doğru önerebilir.
Shell

2
@Chathuranga u herhangi bir ayın asgari tarihinin ne olacağını biliyorum .... ama soru şu anki ayın son tarihidir .. u böyle alabilirsiniz .. mevcut tarihte 1 ay ekleyin ve bundan eksi 1 gün date .. now u şu anki ayın son tarihini göreceksiniz
Shell

Yanıtlar:


480

DateTimeyapı, değer aralığını değil, yalnızca bir değeri saklar. MinValueve yapı MaxValueörnekleri için olası değerler aralığını tutan statik alanlardır DateTime. Bu alanlar statiktir ve belirli bir örneğiyle ilişkili değildir DateTime. Kendilerini yazmakla ilgilidirler DateTime.

Önerilen okuma: statik (C # Referans)

GÜNCELLEME: Ay aralığını alma:

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

16
Buraya seçici olduğumu biliyorum ama olmamalı lastDayofMontholmak firstDayOfMonth.AddMonths(1).AddSeconds(-1);?
Karl Gjertsen

36
@KarlGjertsen yeterince seçici değilsin :) Mükemmel bir çözüm olacak AddTicks(-1), ancak zaman bölümünü umursamıyorsak ve sadece tarih bölümünü düşünürsek, günler iyi çalışır
Sergey Berezovskiy

7
Şimdi bu seçici! ;-) Soru değerlerin nasıl kullanılacağını söylemez, bu yüzden defansif kodlama eğilimindedir.
Karl Gjertsen

@SergeyBerezovskiy Bu noktayı yükseltmekten nefret ederim ama böyle bir DateTime'ı yeni çıkardığınızda saat dilimi bilgilerini kaybetmez misiniz? Bunun gibi yeni bir örnek oluşturduğunuzda, orijinal DateTime örneğine eklenen saat dilimi bilgileri kaybolur.
Marko

2
@KarlGjertsen, sen ben şahsen do ... Picky görmek istiyorum < firstDayOfNextMonthyerine <= lastDayOfMonth. Bu şekilde, ayrıntı düzeyinden bağımsız olarak her zaman çalışır. (Eminim keneler iyi olacak, ama geleceğin ne getirdiğini kim bilebilir ... nanoticks?)
adam0101

100

Bu @Sergey ve @ Steffen'ın cevapları hakkında daha uzun bir yorum. Geçmişte kendime benzer bir kod yazdıktan sonra , netliğin de önemli olduğunu hatırlarken en çok neyin performans gösterdiğini kontrol etmeye karar verdim .

Sonuç

İşte 10 milyon yineleme için örnek bir test çalıştırması sonucu:

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

kod

Ben kullanılan LINQPad 4 açık derleyici optimizasyon testler (C # Program mod). Açıklık ve rahatlık için Uzantı yöntemleri olarak kabul edilen test edilmiş kod:

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

}

analiz

Bu sonuçlardan bazıları beni şaşırttı.

Çok fazla olmamasına rağmen , testin çoğu çalışmasından FirstDayOfMonth_AddMethodbiraz daha hızlıydı FirstDayOfMonth_NewMethod. Ancak, ikincisinin biraz daha net bir niyeti olduğunu düşünüyorum ve bu yüzden bunun için bir tercihim var.

LastDayOfMonth_AddMethodkarşı net bir kaybeden oldu LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethodve LastDayOfMonth_NewMethodWithReuseOfExtMethod. En hızlı üç arasında çok fazla bir şey yok ve bu yüzden kişisel tercihinize bağlı. LastDayOfMonth_NewMethodWithReuseOfExtMethodBaşka bir yararlı uzantı yöntemini yeniden kullanmasıyla netliği seçiyorum . IMHO'nun amacı daha açık ve küçük performans maliyetini kabul etmeye hazırım.

LastDayOfMonth_SpecialCaseo tarihi zaten hesaplamış olabileceğiniz özel durumda ayın ilkini sağladığınızı DateTime.DaysInMonthve sonucu almak için add yöntemini kullandığını varsayar . Bu, diğer versiyonlardan daha hızlı, beklediğiniz gibi, ancak hıza karşı çaresiz bir ihtiyaç duymadıkça, bu özel durumu cephaneliğinizde görmüyorum.

Sonuç

İşte benim seçimler ile bir uzatma yöntemi sınıfı ve genel olarak @Steffen ile anlaşma inanıyorum:

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

Eğer bu kadar ilerlemişseniz, zaman ayırdığınız için teşekkürler! Eğlenceliydi: ¬). Bu algoritmalar için başka önerileriniz varsa lütfen yorum yapın.


5
Ancak çaba için çok daha az kredi var. Yararlı!
Dion

2
Teşekkürler @DionV. - Takdir edilmek güzel! Acele ederken kısa cevaplar harika ama takip etmek için daha derin bir analizin genellikle yararlı olduğunu düşünüyorum.
WooWaaBob

Başka bir alternatifi kaçırdınız: LastDayOfMonth_AddMethod_SpecialCase(veya bunun gibi bir şey). Ayın ilk gününü parametre olarak beklerken, en hızlısı ne olmalı diye düşünüyorum LastDayOfMonth_AddMethod! Yani bu kadar basit olurdu:return value.AddMonths(1).AddDays(-1);
Andrew

1
Thanks @Andrew ve işte bunu kullanarak sonuçlarım: LastDayOfMonth_SpecialCase () için 2835 ms ve; LastDayOfMonth_AddMethod_SpecialCase () için 4685 ms. Yapı oluşturma zamanı düşünüldüğünde muhtemelen mantıklıdır ve DateTime'ın dahili temsili muhtemelen gün eklemeyi basit bir işlem haline getirir, ancak ayları daha karmaşık bir algoritma ekler.
WooWaaBob

15

.Net API ile ay aralığı elde etme (başka bir yolla):

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

7

" Last day of month" aslında " First day of *next* month, minus 1" dir. İşte kullandığım, "DaysInMonth" yöntemine gerek yok:

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

NOT: Burada olmamamın nedeni AddMinutes(-1), AddDays(-1)burada bir tarih dönemi için raporlama için genellikle bu tarih işlevlerine ihtiyaç duymanızdır ve bir dönem için rapor oluşturduğunuzda, "bitiş tarihi" aslında Oct 31 2015 23:59:59raporunuzun doğru çalışması için böyle bir şey olmalıdır. - ayın son gününe ait tüm veriler dahil.

Yani aslında burada "ayın son anını " alıyorsunuz . Son gün değil.

Tamam, şimdi çeneni kapatacağım.


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

Genellikle yalnızca kod yanıtlarından kaçının. descriptionKodunuzu açıklamaya yardımcı olacak bir kod eklemeyi düşünün . Teşekkürler
MickyD 26:15

3

Burada, o günün 1 gününü silmek yerine, geçerli ayın ilk günü için bir ay ekleyebilirsiniz.

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

2

Sadece tarihi önemsiyorsanız

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

Eğer zamanı korumak istiyorsanız

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

Aralık ayında dudeeeeeee tamamen başarısız olacak. "13" ayı ile datetime oluşturmaya çalışacak ve böyle bir tarih olmadığı istisnasını atacaktır.
Pawel

13 Aralık'tan beri? Toplam 12 ay var. Hangi takvimi kullanıyorsunuz?
Vitaly

Tarihiniz aralık ayı ise, istisna ile sonuçlanacak bir ay eklemeye çalışır. yeni DateTime (date.Year, 12+ 1, 1, 0, 0, 0, date.Kind) .AddDays (-1); Ondan bir gün çıkarılırsa, datetime oluşturulduktan sonra yapılacaktır, böylece aralık ayı için "13" ayını denerken başarısız olur. Deneyebilirsin.
Pawel

1

Burada kabul edilen cevap, DateTime örneğini dikkate almaz. Örneğin, orijinal DateTime örneğiniz bir UTC Türüyse, yeni bir DateTime örneği oluşturarak daha sonra sunucu ayarlarına göre yerel saat olarak değerlendirilecek Bilinmeyen Tür örneği yapacaksınız. Bu nedenle, ayın ilk ve son tarihini almanın daha uygun yolu şudur:

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

Bu şekilde orijinal DateTime örneğinin türü korunur.


1

Bunu dene:

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

1

Bunu benim senaryomda kullandım (benim için çalışıyor) ama sadece tarihe ve zamana gerek kalmadan tam bir tarihe ihtiyacım vardı.

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

1

Bunu bir deneyin. Temel olarak, geçen gün sayısını hesaplar DateTime.Now, daha sonra bir gün çıkarır ve geçerli ayın ilkini bulmak için yeni değeri kullanır. Oradan bunu kullanır DateTimeve bir .AddMonths(-1)önceki ayın ilkini almak için kullanır .

Geçen ayın son günü Getting yapar temelde bunun dışında aynı şey ekler aydaki gün ve sayısı birini çıkarır bundan değeri DateTime.Now.AddDayssize bir önceki ayın son günü vererek.

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

0

Fars kültürü için

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

Bunu yapabilirsin

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

-1

bunu yapmanın kolay yolu

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

Bu kod, "yeni DataFim.Text" nedeniyle derlenmiyor.
Wazner

-1
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)));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.