Lấy ngày đầu tiên và ngày cuối cùng của tháng, sử dụng một đối tượng DateTime đã cho


196

Tôi muốn có được ngày đầu tiên và ngày cuối cùng của tháng có một ngày nhất định. Ngày đến từ một giá trị trong trường UI.

Nếu tôi đang sử dụng công cụ chọn thời gian tôi có thể nói

var maxDay = dtpAttendance.MaxDate.Day;

Nhưng tôi đang cố lấy nó từ một đối tượng DateTime. Vì vậy, nếu tôi có ...

DateTime dt = DateTime.today;

Làm thế nào để có được ngày đầu tiên và ngày cuối cùng của tháng dt?


Không rõ bạn đang hỏi gì. Có một giá trị được lưu trữ trong _Datebiến. "Tối thiểu và tối đa" bạn đang cố gắng để có được từ giá trị đó là gì?
David

nó đang bị hạ thấp bởi vì mọi người đang tự hỏi tại sao bạn lại muốn thực hiện một suy nghĩ như vậy và nơi bạn sẽ sử dụng một thứ như vậy. Bạn không nói cho chúng tôi bất cứ điều gì về vấn đề ban đầu của bạn ở đây
Mo Patel

Nó là tốt hơn để hỏi những gì bạn muốn làm gì? không như thế Bạn muốn làm thế nào? có thể sử dụng khác có thể đề nghị bạn chính xác.
Shell

2
@Chathuranga u biết ngày nào sẽ là ngày tối thiểu của bất kỳ tháng nào .... nhưng câu hỏi là ngày cuối cùng của tháng hiện tại là gì .. bạn có thể nhận được như thế này .. thêm 1 tháng vào ngày hiện tại và trừ đi 1 ngày kể từ đó ngày .. bây giờ bạn sẽ có được ngày cuối cùng của tháng hiện tại
Shell

Câu trả lời:


472

DateTimecấu trúc chỉ lưu trữ một giá trị, không phạm vi giá trị. MinValueMaxValuelà các trường tĩnh, chứa phạm vi các giá trị có thể cho các thể hiện của DateTimecấu trúc. Các trường này là tĩnh và không liên quan đến trường hợp cụ thể của DateTime. Họ liên quan đến DateTimeloại chính nó.

Đề nghị đọc: tĩnh (Tham khảo C #)

CẬP NHẬT: Bắt phạm vi tháng:

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

16
Tôi biết tôi đang kén chọn ở đây, nhưng không lastDayofMonthnên firstDayOfMonth.AddMonths(1).AddSeconds(-1);?
Karl Gjertsen

36
@KarlGjertsen bạn không đủ kén chọn :) Giải pháp hoàn hảo sẽ là AddTicks(-1), nhưng nếu chúng ta không quan tâm đến phần thời gian và chỉ nghĩ về phần ngày, thì ngày làm việc tốt
Serge Berezovskiy

7
Bây giờ đang được kén chọn! ;-) Câu hỏi không cho biết các giá trị sẽ được sử dụng như thế nào, vì vậy tôi có xu hướng mã hóa phòng thủ.
Karl Gjertsen

@SergeyBerezovskiy Tôi ghét tăng điểm này nhưng bạn không bị mất thông tin múi giờ khi bạn mới cập nhật DateTime như thế này? Bất cứ thông tin múi giờ nào được đính kèm với phiên bản DateTime ban đầu đều bị mất khi bạn tạo một phiên bản mới như thế này.
Marko

2
@KarlGjertsen, bạn muốn thấy kén chọn ... Cá nhân tôi làm < firstDayOfNextMonththay vì <= lastDayOfMonth. Bằng cách đó, nó sẽ luôn hoạt động bất kể độ chi tiết. (Tôi chắc chắn bọ ve sẽ ổn, nhưng ai biết được tương lai mang lại gì ... nanoticks?)
adam0101

99

Đây là một nhận xét dài hơn về câu trả lời của @Sergey và @ Steffen. Trước đây tôi đã viết mã tương tự, tôi quyết định kiểm tra xem cái gì hiệu quả nhất trong khi nhớ rằng sự rõ ràng cũng quan trọng.

Kết quả

Dưới đây là kết quả chạy thử nghiệm ví dụ cho 10 triệu lần lặp:

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

Tôi đã sử dụng LINQPad 4 (trong chế độ Chương trình C #) để chạy thử nghiệm với bật tối ưu hóa trình biên dịch. Dưới đây là mã được thử nghiệm bao gồm các phương thức Mở rộng để rõ ràng và thuận tiện:

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

}

Phân tích

Tôi đã ngạc nhiên bởi một số trong những kết quả này.

Mặc dù không có nhiều trong đó nhưng nó FirstDayOfMonth_AddMethodnhanh hơn một chút so với FirstDayOfMonth_NewMethodhầu hết các lần chạy thử. Tuy nhiên, tôi nghĩ rằng cái sau có một ý định rõ ràng hơn một chút và vì vậy tôi có một sở thích cho điều đó.

LastDayOfMonth_AddMethodlà một kẻ thua cuộc rõ ràng chống lại LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethodLastDayOfMonth_NewMethodWithReuseOfExtMethod. Giữa ba người nhanh nhất không có gì nhiều trong đó và do đó, nó tùy thuộc vào sở thích cá nhân của bạn. Tôi chọn sự rõ ràng LastDayOfMonth_NewMethodWithReuseOfExtMethodvới việc sử dụng lại một phương pháp mở rộng hữu ích khác. IMHO ý định của nó rõ ràng hơn và tôi sẵn sàng chấp nhận chi phí hiệu suất nhỏ.

LastDayOfMonth_SpecialCase giả sử bạn đang cung cấp ngày đầu tiên của tháng trong trường hợp đặc biệt mà bạn có thể đã tính ngày đó và nó sử dụng phương thức add với DateTime.DaysInMonth để có kết quả. Điều này nhanh hơn các phiên bản khác, như bạn mong đợi, nhưng trừ khi bạn đang rất cần tốc độ, tôi không thấy vấn đề có trường hợp đặc biệt này trong kho vũ khí của bạn.

Phần kết luận

Đây là lớp phương thức mở rộng với các lựa chọn của tôi và theo thỏa thuận chung với @Steffen tôi tin rằng:

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

Nếu bạn đã đạt được điều này, cảm ơn bạn đã dành thời gian! Thật là vui:). Hãy bình luận nếu bạn có bất kỳ đề xuất nào khác cho các thuật toán này.


5
Bạn có quá ít tín dụng cho nỗ lực của bạn mặc dù. Nó rất hữu ích!
Dion V.

2
Cảm ơn @DionV. - thật tốt khi được đánh giá cao! Câu trả lời ngắn là tuyệt vời khi bạn đang vội nhưng tôi nghĩ một số phân tích sâu hơn để làm theo thường hữu ích.
WooWaaBob

Bạn đã bỏ lỡ một lựa chọn khác: LastDayOfMonth_AddMethod_SpecialCase(hoặc một cái gì đó như thế). Mong đợi ngày đầu tiên của tháng là tham số, tôi nghĩ nhanh nhất nên làm gì LastDayOfMonth_AddMethod! Vì vậy, điều đó sẽ đơn giản như:return value.AddMonths(1).AddDays(-1);
Andrew

1
Cảm ơn @Andrew và đây là kết quả của tôi khi sử dụng: 2835 ms cho LastDayOfMonth_ecialCase () và; 4685 ms cho LastDayOfMonth_AddMethod_ecialCase (). Điều này có thể có ý nghĩa khi xem xét thời gian tạo cấu trúc và biểu diễn bên trong của DateTime có thể làm cho việc thêm ngày trở thành một thao tác đơn giản nhưng thêm tháng là một thuật toán phức tạp hơn.
WooWaaBob

15

Nhận phạm vi tháng với API .Net (chỉ là một cách khác):

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" thực sự là " First day of *next* month, minus 1". Vì vậy, đây là những gì tôi sử dụng, không cần phương thức "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);
}

LƯU Ý: Lý do tôi sử dụng AddMinutes(-1), không phải AddDays(-1)ở đây là vì thông thường bạn cần các hàm ngày này để báo cáo cho một khoảng thời gian và khi bạn tạo báo cáo cho một khoảng thời gian, "ngày kết thúc" thực sự phải giống như Oct 31 2015 23:59:59vậy để báo cáo của bạn hoạt động chính xác - bao gồm tất cả các dữ liệu từ ngày cuối cùng của tháng.

Tức là bạn thực sự có được " khoảnh khắc cuối cùng của tháng" ở đây. Không phải ngày cuối cùng.

OK, tôi sẽ im lặng ngay bây giờ.


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

Nói chung tránh các câu trả lời chỉ có mã. Xem xét thêm một descriptiongiúp để giải thích mã của bạn. Cảm ơn
MickyD

3

Tại đây bạn có thể thêm một tháng cho ngày đầu tiên của tháng hiện tại thay vì xóa 1 ngày kể từ ngày đó.

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

2

Nếu bạn chỉ quan tâm đến ngày

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

Nếu bạn muốn giữ thời gian

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

Nó sẽ hoàn toàn thất bại trong tháng mười hai dudeeeeeee. nó sẽ cố gắng tạo datetime với tháng "13" và đưa ra ngoại lệ rằng không có ngày đó.
Pawel

Từ khi nào là tháng 12? Có tổng cộng 12 tháng. Bạn sử dụng lịch nào?
Vitaly

Nếu ngày của bạn là tháng mười hai thì nó sẽ cố gắng thêm một tháng sẽ dẫn đến ngoại lệ. DateTime mới (date.Year, 12+ 1, 1, 0, 0, 0, date.Kind) .AddDays (-1); Trừ đi một ngày từ nó sẽ được thực hiện sau khi datetime sẽ được tạo ra để cho tháng mười hai, nó sẽ thất bại khi thử ngày cho tháng "13". Bạn có thể thử nó.
Pawel

1

Câu trả lời được chấp nhận ở đây không tính đến loại Ví dụ DateTime. Ví dụ: nếu phiên bản DateTime ban đầu của bạn là Loại UTC thì bằng cách tạo phiên bản DateTime mới, bạn sẽ tạo một phiên bản Loại không xác định, sau đó sẽ được coi là giờ địa phương dựa trên cài đặt máy chủ. Do đó, cách thích hợp hơn để có được ngày đầu tiên và ngày cuối cùng của tháng sẽ là:

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

Bằng cách này, loại bản gốc của DateTime được giữ nguyên.


1

Hãy thử cái này:

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

1

Tôi đã sử dụng điều này trong kịch bản của mình (hoạt động cho tôi) nhưng tôi cần một ngày đầy đủ mà không cần cắt xén nó chỉ đến ngày và không có thời gian.

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

1

Hãy thử cái này Về cơ bản, nó tính toán số ngày đã trôi qua DateTime.Now, sau đó trừ đi một ngày từ đó và sử dụng giá trị mới để tìm ngày đầu tiên của tháng hiện tại. Từ đó, nó sử dụng DateTimevà sử dụng .AddMonths(-1)để có được đầu tiên của tháng trước.

Lấy ngày cuối cùng của tháng trước về cơ bản là điều tương tự ngoại trừ việc thêm một vào số ngày trong tháng và trừ đi giá trị đó DateTime.Now.AddDays, mang lại cho bạn ngày cuối cùng của tháng trước.

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

Đối với văn hóa Ba Tư

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

Bạn có thể làm được

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

-1

cách dễ dàng để làm điều đó

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

Mã này không biên dịch vì "DataFim.Text mới".
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)));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.