Mendapatkan hari pertama dan terakhir dalam sebulan, menggunakan objek DateTime yang diberikan


196

Saya ingin mendapatkan hari pertama dan hari terakhir bulan di mana tanggal tertentu berada. Tanggal berasal dari nilai di bidang UI.

Jika saya menggunakan pemilih waktu, saya bisa katakan

var maxDay = dtpAttendance.MaxDate.Day;

Tapi saya mencoba untuk mendapatkannya dari objek DateTime. Jadi jika saya punya ini ...

DateTime dt = DateTime.today;

Bagaimana cara mendapatkan hari pertama dan hari terakhir bulan itu dt?


Tidak jelas apa yang Anda minta. Ada nilai tunggal yang disimpan dalam _Datevariabel. Apa "min dan maks" yang Anda coba dapatkan dari nilai itu?
David

itu semakin turun karena orang-orang bertanya-tanya mengapa Anda ingin melakukan pemikiran seperti itu dan di mana Anda akan menggunakan hal seperti itu. Anda tidak memberi tahu kami apa pun tentang masalah awal Anda di sini
Mo Patel

Lebih baik bertanya apa yang ingin Anda lakukan? not like that Bagaimana Anda ingin melakukannya? Semoga penggunaan lain dapat menyarankan Anda dengan benar.
Shell

2
@ Churangurang kamu tahu apa yang akan menjadi tanggal minimum setiap bulan .... tetapi pertanyaannya adalah apa tanggal terakhir bulan ini .. kamu bisa mendapatkan seperti ini .. tambahkan 1 bulan di tanggal sekarang dan minus 1 hari dari itu date .. sekarang kamu akan mendapatkan tanggal terakhir bulan ini
Shell

Jawaban:


472

DateTimestruktur hanya menyimpan satu nilai, bukan rentang nilai. MinValuedan MaxValuemerupakan bidang statis, yang menyimpan rentang nilai yang mungkin untuk instance DateTimestruktur. Bidang-bidang ini statis dan tidak berhubungan dengan contoh khusus DateTime. Mereka berhubungan dengan DateTimemengetik sendiri.

Bacaan yang disarankan: statis (C # Referensi)

UPDATE: Memperoleh rentang bulan:

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

16
Aku tahu aku menjadi pemilih di sini, tetapi seharusnya tidak lastDayofMonthmenjadi firstDayOfMonth.AddMonths(1).AddSeconds(-1);?
Karl Gjertsen

36
@KarlGjertsen Anda tidak cukup pilih-pilih :) Solusi sempurna akan AddTicks(-1), tetapi jika kita tidak peduli tentang waktu bagian dan hanya memikirkan bagian tanggal, maka hari-hari akan baik
Sergey Berezovskiy

7
Sekarang sedang pilih-pilih! ;-) Pertanyaannya tidak mengatakan bagaimana nilai akan digunakan, jadi saya cenderung kode defensif.
Karl Gjertsen

@SergeyBerezovskiy Saya benci untuk meningkatkan poin ini tetapi tidakkah Anda kehilangan informasi zona waktu saat Anda baru menggunakan DateTime seperti ini? Apa pun info zona waktu yang dilampirkan pada instance DateTime asli hilang ketika Anda membuat instance baru seperti ini.
Marko

2
@KarlGjertsen, Anda ingin melihat pemilih ... Saya pribadi < firstDayOfNextMonthbukan <= lastDayOfMonth. Dengan cara itu akan selalu berhasil terlepas dari rinciannya. (Saya yakin kutu akan baik-baik saja, tetapi siapa yang tahu apa yang akan terjadi di masa depan ... nanoticks?)
adam0101

99

Ini lebih merupakan komentar panjang tentang jawaban @Sergey dan @ Steffen. Setelah menulis kode yang sama sendiri di masa lalu, saya memutuskan untuk memeriksa apa yang paling performan sambil mengingat bahwa kejelasan juga penting.

Hasil

Berikut ini adalah contoh hasil uji coba untuk 10 juta iterasi:

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

Kode

Saya menggunakan LINQPad 4 (dalam mode Program C #) untuk menjalankan tes dengan optimasi kompiler dihidupkan. Berikut adalah kode yang diuji yang diperhitungkan sebagai metode Ekstensi untuk kejelasan dan kenyamanan:

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

}

Analisis

Saya terkejut dengan beberapa hasil ini.

Meskipun tidak banyak di dalamnya, FirstDayOfMonth_AddMethoditu sedikit lebih cepat daripada FirstDayOfMonth_NewMethoddi sebagian besar menjalankan tes. Namun, saya pikir yang terakhir memiliki niat yang sedikit lebih jelas sehingga saya memiliki preferensi untuk itu.

LastDayOfMonth_AddMethodjelas kalah melawan LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethoddan LastDayOfMonth_NewMethodWithReuseOfExtMethod. Antara tiga tercepat tidak ada banyak di dalamnya sehingga turun ke preferensi pribadi Anda. Saya memilih kejelasan LastDayOfMonth_NewMethodWithReuseOfExtMethoddengan menggunakan kembali metode ekstensi lain yang bermanfaat. IMHO maksudnya lebih jelas dan saya bersedia menerima biaya kinerja yang kecil.

LastDayOfMonth_SpecialCase mengasumsikan Anda memberikan yang pertama bulan dalam kasus khusus di mana Anda mungkin sudah menghitung tanggal itu dan menggunakan metode add dengan DateTime.DaysInMonth untuk mendapatkan hasilnya. Ini lebih cepat daripada versi lain, seperti yang Anda harapkan, tetapi kecuali Anda sangat membutuhkan kecepatan, saya tidak melihat gunanya memiliki case khusus ini di gudang senjata Anda.

Kesimpulan

Berikut ini adalah kelas metode ekstensi dengan pilihan saya dan dalam perjanjian umum dengan @Steffen saya percaya:

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

Jika Anda sudah sejauh ini, terima kasih atas waktunya! Sudah menyenangkan: ¬). Berikan komentar jika Anda memiliki saran lain untuk algoritme ini.


5
Anda memiliki kredit terlalu sedikit untuk usaha Anda sekalipun. Ini berguna!
Dion V.

2
Terima kasih @DionV. - senang dihargai! Jawaban singkat itu bagus ketika Anda sedang terburu-buru tetapi saya pikir beberapa analisis yang lebih dalam untuk mengikuti sering kali berguna.
WooWaaBob

Anda melewatkan alternatif lain: LastDayOfMonth_AddMethod_SpecialCase(atau sesuatu seperti itu). Mengharapkan hari pertama bulan sebagai parameter, saya pikir tercepat harus apa LastDayOfMonth_AddMethod! Jadi itu akan sesederhana:return value.AddMonths(1).AddDays(-1);
Andrew

1
Terima kasih @Andrew dan inilah hasil saya menggunakan itu: 2835 ms untuk LastDayOfMonth_SpecialCase (), dan; 4685 ms untuk LastDayOfMonth_AddMethod_SpecialCase (). Yang mungkin masuk akal ketika mempertimbangkan waktu pembuatan struct dan bahwa representasi internal DateTime mungkin membuat menambahkan hari operasi sederhana tetapi menambahkan bulan algoritma yang lebih kompleks.
WooWaaBob

15

Mendapatkan rentang bulan dengan .Net API (dengan cara lain):

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

6

" Last day of month" sebenarnya " First day of *next* month, minus 1". Jadi inilah yang saya gunakan, tidak perlu metode "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);
}

CATATAN: Alasan saya menggunakan AddMinutes(-1), bukan di AddDays(-1)sini adalah karena biasanya Anda memerlukan fungsi tanggal ini untuk pelaporan untuk beberapa periode tanggal, dan ketika Anda membuat laporan untuk suatu periode, "tanggal akhir" sebenarnya harus berupa sesuatu Oct 31 2015 23:59:59sehingga laporan Anda berfungsi dengan benar - termasuk semua data dari hari terakhir bulan ini.

Yaitu Anda benar-benar mendapatkan " momen terakhir bulan ini" di sini. Bukan hari terakhir.

Oke, saya akan tutup mulut sekarang.


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

Umumnya menghindari jawaban hanya kode. Pertimbangkan untuk menambahkan descriptionyang membantu menjelaskan kode Anda. Terima kasih
MickyD

3

Di sini Anda dapat menambahkan satu bulan untuk hari pertama bulan ini daripada menghapus 1 hari dari hari itu.

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

2

Jika Anda hanya peduli dengan tanggalnya

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

Jika Anda ingin menghemat waktu

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

Ini akan benar-benar gagal pada bulan desember deeeeeeeee. itu akan mencoba untuk membuat datetime dengan bulan "13" dan melemparkan pengecualian bahwa tidak ada tanggal seperti itu.
Pawel

Sejak kapan Desember 13? Ada total 12 bulan. Kalender apa yang Anda gunakan?
Vitaly

Jika tanggal Anda adalah Desember maka akan mencoba menambahkan satu bulan yang akan menghasilkan pengecualian. DateTime baru (date.Year, 12+ 1, 1, 0, 0, 0, date.Kind) .AddDays (-1); Mengurangkan satu hari darinya akan dilakukan setelah datetime akan dibuat sehingga untuk bulan desember akan gagal ketika mencoba tanggal untuk bulan "13". Kamu bisa mencobanya.
Pawel

1

Jawaban yang diterima di sini tidak memperhitungkan contoh Jenis DateTime. Misalnya jika instance DateTime asli Anda adalah Jenis UTC maka dengan membuat instance DateTime baru Anda akan membuat instance Jenis Tidak Dikenal yang kemudian akan diperlakukan sebagai waktu lokal berdasarkan pengaturan server. Oleh karena itu cara yang lebih tepat untuk mendapatkan tanggal pertama dan terakhir bulan ini adalah sebagai berikut:

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

Dengan cara ini Jenis asli dari DateTime disimpan.


1

Coba yang ini:

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

1

Saya menggunakan ini dalam skrip saya (berfungsi untuk saya) tetapi saya membutuhkan tanggal penuh tanpa perlu memotongnya menjadi hanya tanggal dan tidak ada waktu.

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

1

Cobalah ini. Ini pada dasarnya menghitung jumlah hari yang telah berlalu DateTime.Now, kemudian kurangi satu dari itu dan menggunakan nilai baru untuk menemukan yang pertama dari bulan berjalan. Dari sana ia menggunakan itu DateTimedan menggunakan .AddMonths(-1)untuk mendapatkan yang pertama dari bulan sebelumnya.

Mendapatkan hari terakhir bulan lalu pada dasarnya melakukan hal yang sama kecuali itu menambah satu ke jumlah hari dalam sebulan dan mengurangi nilai itu dari DateTime.Now.AddDays, memberikan Anda hari terakhir bulan sebelumnya.

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

Untuk budaya Persia

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

Kamu bisa melakukannya

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

-1

cara mudah untuk melakukannya

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

Kode ini tidak dikompilasi karena "DataFim.Text baru".
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)));
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.