주어진 날짜가있는 달의 첫날과 마지막 날을 얻고 싶습니다. 날짜는 UI 필드의 값에서 비롯됩니다.
시간 선택기를 사용하는 경우
var maxDay = dtpAttendance.MaxDate.Day;
그러나 DateTime 객체에서 가져 오려고합니다. 이걸 가지고 있다면 …
DateTime dt = DateTime.today;
에서 첫날과 마지막 날을 얻는 방법은 dt
무엇입니까?
답변
DateTime
구조체는 값 범위가 아닌 하나의 값만 저장합니다. MinValue
및 MaxValue
인스턴스에 대한 가능한 값의 범위를 유지 정적 필드이다 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_AddMethodWithDaysInMonth
, LastDayOfMonth_NewMethod
그리고 LastDayOfMonth_NewMethodWithReuseOfExtMethod
. 가장 빠른 세 가지 사이에는 그다지 많은 것이 없으므로 개인 취향에 달려 있습니다. LastDayOfMonth_NewMethodWithReuseOfExtMethod
또 다른 유용한 확장 방법을 재사용 하여 명확성을 선택합니다 . IMHO의 의도가 명확하고 작은 성능 비용을 기꺼이 받아들입니다.
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());
}
}
당신이 이것을 멀리 가지고 있다면, 시간 내 주셔서 감사합니다! 재미있었습니다 :)). 이 알고리즘에 대한 다른 제안 사항이 있으면 의견을 보내주십시오.
답변
.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 일을 삭제하는 것보다 현재 달의 1 일에 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);