如何在c#中计算两个日期之间的月差?
c#中是否有相当于VB的DateDiff()方法。我需要找出相隔数年的两个日期之间的月差。文档说我可以像这样使用TimeSpan:
TimeSpan ts = date1 - date2;
但这里的数据是以天为单位的。我不想把这个数字除以30,因为不是每个月都是30天,而且两个操作数的值相差很大,所以我担心除以30可能会得到错误的值。
有什么建议吗?
如何在c#中计算两个日期之间的月差?
c#中是否有相当于VB的DateDiff()方法。我需要找出相隔数年的两个日期之间的月差。文档说我可以像这样使用TimeSpan:
TimeSpan ts = date1 - date2;
但这里的数据是以天为单位的。我不想把这个数字除以30,因为不是每个月都是30天,而且两个操作数的值相差很大,所以我担心除以30可能会得到错误的值。
有什么建议吗?
当前回答
public static int PayableMonthsInDuration(DateTime StartDate, DateTime EndDate)
{
int sy = StartDate.Year; int sm = StartDate.Month; int count = 0;
do
{
count++;if ((sy == EndDate.Year) && (sm >= EndDate.Month)) { break; }
sm++;if (sm == 13) { sm = 1; sy++; }
} while ((EndDate.Year >= sy) || (EndDate.Month >= sm));
return (count);
}
这个解决方案是用于租金/订阅计算的,其中的差异并不意味着减法,它意味着这两个日期之间的跨度。
其他回答
这里有一个简单的解决方案,至少对我来说是有效的。它可能不是最快的,因为它在循环中使用了很酷的DateTime的AddMonth功能:
public static int GetMonthsDiff(DateTime start, DateTime end)
{
if (start > end)
return GetMonthsDiff(end, start);
int months = 0;
do
{
start = start.AddMonths(1);
if (start > end)
return months;
months++;
}
while (true);
}
基于上面出色的DateTimeSpan工作,我将代码规范化了一些;这似乎很有效:
public class DateTimeSpan
{
private DateTimeSpan() { }
private DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
{
Years = years;
Months = months;
Days = days;
Hours = hours;
Minutes = minutes;
Seconds = seconds;
Milliseconds = milliseconds;
}
public int Years { get; private set; } = 0;
public int Months { get; private set; } = 0;
public int Days { get; private set; } = 0;
public int Hours { get; private set; } = 0;
public int Minutes { get; private set; } = 0;
public int Seconds { get; private set; } = 0;
public int Milliseconds { get; private set; } = 0;
public static DateTimeSpan CompareDates(DateTime StartDate, DateTime EndDate)
{
if (StartDate.Equals(EndDate)) return new DateTimeSpan();
DateTimeSpan R = new DateTimeSpan();
bool Later;
if (Later = StartDate > EndDate)
{
DateTime D = StartDate;
StartDate = EndDate;
EndDate = D;
}
// Calculate Date Stuff
for (DateTime D = StartDate.AddYears(1); D < EndDate; D = D.AddYears(1), R.Years++) ;
if (R.Years > 0) StartDate = StartDate.AddYears(R.Years);
for (DateTime D = StartDate.AddMonths(1); D < EndDate; D = D.AddMonths(1), R.Months++) ;
if (R.Months > 0) StartDate = StartDate.AddMonths(R.Months);
for (DateTime D = StartDate.AddDays(1); D < EndDate; D = D.AddDays(1), R.Days++) ;
if (R.Days > 0) StartDate = StartDate.AddDays(R.Days);
// Calculate Time Stuff
TimeSpan T1 = EndDate - StartDate;
R.Hours = T1.Hours;
R.Minutes = T1.Minutes;
R.Seconds = T1.Seconds;
R.Milliseconds = T1.Milliseconds;
// Return answer. Negate values if the Start Date was later than the End Date
if (Later)
return new DateTimeSpan(-R.Years, -R.Months, -R.Days, -R.Hours, -R.Minutes, -R.Seconds, -R.Milliseconds);
return R;
}
}
简单的修复。工作的100%
var exactmonth = (date1.Year - date2.Year) * 12 + date1.Month -
date2.Month + (date1.Day >= date2.Day ? 0 : -1);
Console.WriteLine(exactmonth);
这个简单的静态函数计算两个Datetimes之间的月份分数。
1.1. 到31.1。= 1.0 1.4. 到15.4。= 0.5 16.4. 到30.4。= 0.5 1.3. 到1.4。= 1 + 1/30
该函数假设第一个日期比第二个日期小。要处理负时间间隔,可以通过在开始时引入符号和变量交换来轻松地修改函数。
public static double GetDeltaMonths(DateTime t0, DateTime t1)
{
DateTime t = t0;
double months = 0;
while(t<=t1)
{
int daysInMonth = DateTime.DaysInMonth(t.Year, t.Month);
DateTime endOfMonth = new DateTime(t.Year, t.Month, daysInMonth);
int cutDay = endOfMonth <= t1 ? daysInMonth : t1.Day;
months += (cutDay - t.Day + 1) / (double) daysInMonth;
t = new DateTime(t.Year, t.Month, 1).AddMonths(1);
}
return Math.Round(months,2);
}
这是对Kirk Woll的回答的回应。我还没有足够的声望点来回复评论……
我喜欢Kirk的解决方案,并打算无耻地窃取它并在我的代码中使用它,但当我仔细查看它时,我意识到它太复杂了。不必要的切换和循环,以及使用毫无意义的公共构造函数。
以下是我的改写:
public class DateTimeSpan {
private DateTime _date1;
private DateTime _date2;
private int _years;
private int _months;
private int _days;
private int _hours;
private int _minutes;
private int _seconds;
private int _milliseconds;
public int Years { get { return _years; } }
public int Months { get { return _months; } }
public int Days { get { return _days; } }
public int Hours { get { return _hours; } }
public int Minutes { get { return _minutes; } }
public int Seconds { get { return _seconds; } }
public int Milliseconds { get { return _milliseconds; } }
public DateTimeSpan(DateTime date1, DateTime date2) {
_date1 = (date1 > date2) ? date1 : date2;
_date2 = (date2 < date1) ? date2 : date1;
_years = _date1.Year - _date2.Year;
_months = (_years * 12) + _date1.Month - _date2.Month;
TimeSpan t = (_date2 - _date1);
_days = t.Days;
_hours = t.Hours;
_minutes = t.Minutes;
_seconds = t.Seconds;
_milliseconds = t.Milliseconds;
}
public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) {
return new DateTimeSpan(date1, date2);
}
}
用法1,基本相同:
void Main()
{
DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
var dateSpan = new DateTimeSpan(compareTo, now);
Console.WriteLine("Years: " + dateSpan.Years);
Console.WriteLine("Months: " + dateSpan.Months);
Console.WriteLine("Days: " + dateSpan.Days);
Console.WriteLine("Hours: " + dateSpan.Hours);
Console.WriteLine("Minutes: " + dateSpan.Minutes);
Console.WriteLine("Seconds: " + dateSpan.Seconds);
Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}
Usage2类似:
void Main()
{
DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
Console.WriteLine("Years: " + DateTimeSpan.CompareDates(compareTo, now).Years);
Console.WriteLine("Months: " + DateTimeSpan.CompareDates(compareTo, now).Months);
Console.WriteLine("Days: " + DateTimeSpan.CompareDates(compareTo, now).Days);
Console.WriteLine("Hours: " + DateTimeSpan.CompareDates(compareTo, now).Hours);
Console.WriteLine("Minutes: " + DateTimeSpan.CompareDates(compareTo, now).Minutes);
Console.WriteLine("Seconds: " + DateTimeSpan.CompareDates(compareTo, now).Seconds);
Console.WriteLine("Milliseconds: " + DateTimeSpan.CompareDates(compareTo, now).Milliseconds);
}