DateTime difference returing correct no of months and or even years?
Is there any built-in function how can I get the difference between tho DateTime objects in better way than just开发者_高级运维 number of days? I mean something like 1 month, 23 days. I find it pretty hard to calculate due to differnet number of days in each month, leap years etc. Thanks
Have a look at Noda Time. It's not production-ready in general yet, but the relevant bits may work well enough for your current requirements :)
Note that TimeSpan
will not do what you want, because "1 month" can mean a different number of days depending on the month, and a TimeSpan
isn't anchored.
In Noda Time, you want a Period
. For example:
LocalDate start = new LocalDate(2010, 4, 15);
LocalDate end = new LocalDate(2010, 6, 19);
Period period = Period.Between(start, end); // Defaults to Year/Month/Day
Console.WriteLine(period.Months); // 2
Console.WriteLine(period.Days); // 4
Note that date/time arithmetic is hard... in some cases "the right answer" isn't at all obvious.
Months can consist of 28, 29, 30, or 31 days; years can be 365 or 366 days. Therefore, problems arise when you try to calculate full units of time for months and years, So if you can assume something then you can check this out
Simple subtraction will do the job:
int months = departure.Months - arrival.Months;
int years = departure.Years - arrival.Years;
//in case multiple years have elapsed .
int months += years * 12;
You obviously would need to do some math when it comes to days, if you dont care about precision if the day difference is negative you will need to subtract one from the month.
And then you could use TimeSpan To get more precision aka elapsed time.
//Microsoft Documentation Example:
DateTime departure = new DateTime(2010, 6, 12, 18, 32, 0);
DateTime arrival = new DateTime(2010, 6, 13, 22, 47, 0);
TimeSpan travelTime = arrival - departure;
Console.WriteLine("{0} - {1} = {2}", arrival, departure, travelTime);
// The example displays the following output:
// 6/13/2010 10:47:00 PM - 6/12/2010 6:32:00 PM = 1.04:15:00
This kind of problem is surprisingly hard to specify for calendar dates. Take a look here for a good calculation of how to compute a person's age in years.
Calculate age in C#
The complexity comes from the edge cases. Obviously Jan 31st is a month after Dec 31st. But, is Feb 28th a month after Jan 31st? In a normal year? In a leap year? Before you can code this you need to specify these kinds of cases.
The birthday algorithm uses a round-down and increment strategy. That will work for month differences as well, given your answer to the question in the previous paragraph.
Here is some code I just wrote to calculate the difference in years, months, and days. It is in the public domain.
public sealed class DateDifference {
int years;
public int Years {
get { return years; }
}
int months;
public int Months {
get { return months; }
}
int days;
public int Days {
get { return days; }
}
public override string ToString()
{
return string.Format("[DateDifference Years={0}, Months={1}, Days={2}]", years, months, days);
}
public DateDifference(DateTime earlier, DateTime later){
if(later<earlier)
throw new ArgumentException("later is earlier than 'earlier'.");
bool isleapday=(earlier.Month==2 && earlier.Day==29);
DateTime tmp=isleapday ? new DateTime(earlier.Year,2,28) : earlier;
while(true){
try {
tmp=tmp.AddYears(1);
if(isleapday && DateTime.IsLeapYear(tmp.Year))
tmp=new DateTime(tmp.Year,2,29);
} catch(ArgumentOutOfRangeException){
break;
}
if(tmp<=later){
years++;
earlier=tmp;
} else {
break;
}
}
// Add months
tmp=earlier;
while(true){
try {
tmp=tmp.AddMonths(1);
if(isleapday && tmp.Day!=29 && tmp.Month!=2)
tmp=new DateTime(tmp.Year,tmp.Month,29);
} catch(ArgumentOutOfRangeException){
break;
}
if(tmp<=later){
months++;
earlier=tmp;
} else {
break;
}
}
tmp=earlier;
while(true){
try {
tmp=tmp.AddDays(1);
} catch(ArgumentOutOfRangeException){
break;
}
if(tmp<=later){
days++;
earlier=tmp;
} else {
break;
}
}
}
}
Example:
var dd=new DateDifference(new DateTime(2010,6,29),new DateTime(2012,2,29));
Console.WriteLine(dd.Years); // displays 1
Console.WriteLine(dd.Months); // displays 8
Console.WriteLine(dd.Days); // displays 0
You can use the DateDiff class of the Time Period Library for .NET:
// ----------------------------------------------------------------------
public void DateDiffSample()
{
DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
Console.WriteLine( "Date1: {0}", date1 );
// > Date1: 08.11.2009 07:13:59
DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
Console.WriteLine( "Date2: {0}", date2 );
// > Date2: 20.03.2011 19:55:28
DateDiff dateDiff = new DateDiff( date1, date2 );
// differences
Console.WriteLine( "DateDiff.Years: {0}", dateDiff.Years );
// > DateDiff.Years: 1
Console.WriteLine( "DateDiff.Quarters: {0}", dateDiff.Quarters );
// > DateDiff.Quarters: 5
Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
// > DateDiff.Months: 16
Console.WriteLine( "DateDiff.Weeks: {0}", dateDiff.Weeks );
// > DateDiff.Weeks: 70
Console.WriteLine( "DateDiff.Days: {0}", dateDiff.Days );
// > DateDiff.Days: 497
Console.WriteLine( "DateDiff.Weekdays: {0}", dateDiff.Weekdays );
// > DateDiff.Weekdays: 71
Console.WriteLine( "DateDiff.Hours: {0}", dateDiff.Hours );
// > DateDiff.Hours: 11940
Console.WriteLine( "DateDiff.Minutes: {0}", dateDiff.Minutes );
// > DateDiff.Minutes: 716441
Console.WriteLine( "DateDiff.Seconds: {0}", dateDiff.Seconds );
// > DateDiff.Seconds: 42986489
// elapsed
Console.WriteLine( "DateDiff.ElapsedYears: {0}", dateDiff.ElapsedYears );
// > DateDiff.ElapsedYears: 1
Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
// > DateDiff.ElapsedMonths: 4
Console.WriteLine( "DateDiff.ElapsedDays: {0}", dateDiff.ElapsedDays );
// > DateDiff.ElapsedDays: 12
Console.WriteLine( "DateDiff.ElapsedHours: {0}", dateDiff.ElapsedHours );
// > DateDiff.ElapsedHours: 12
Console.WriteLine( "DateDiff.ElapsedMinutes: {0}", dateDiff.ElapsedMinutes );
// > DateDiff.ElapsedMinutes: 41
Console.WriteLine( "DateDiff.ElapsedSeconds: {0}", dateDiff.ElapsedSeconds );
// > DateDiff.ElapsedSeconds: 29
} // DateDiffSample
Try this one
public string YearsMonthsDaysDiff(DateTime dateFrom, DateTime dateTo)
{
Int32 mD = DateTime.DaysInMonth(dateTo.Year, dateTo.AddMonths(-1).Month); //first check out days in month before dateTo month
Int32 D1 = dateFrom.Day;
Int32 M1 = dateFrom.Month;
Int32 Y1 = dateFrom.Year;
Int32 D2 = dateTo.Day;
Int32 M2 = dateTo.Month;
Int32 Y2 = dateTo.Year;
// Substract each datetime components accordingly
D2 -= D1;
M2 -= M1;
Y2 -= Y1;
if (D2 < 0)
{
D2 += mD;// D2 is less then D1, then add mD
M2 -= 1; // but, substract 1 from M2
}
if (M2 < 0)
{
M2 += 12; // if M2 is less then M1, then add with 12
Y2 -= 1; // but substract 1 from Y2
}
return Y2.ToString("## years ") + M2.ToString("## months ") + D2.ToString("## days");
}
it works fine for me
Here's a class that allows you to query various properties of the difference of a pair of DateTimes. I just whipped it up now, and am releasing it into the public domain. Do with it as you will, but use it at your own risk.
public static class DateCalcs
{
/// <summary>
/// returns the integer number of years between start and finish
/// </summary>
/// <param name="start">Start DateTime</param>
/// <param name="finish">FinishDateTime</param>
/// <returns></returns>
public static int YearDiff(DateTime start, DateTime finish)
{
DateTime _start, _finish;
bool _negate = (finish < start);
if(_negate)
{
_start = finish;
_finish = start;
}
else
{
_start = start;
_finish = finish;
}
int _diff = 0;
while(_start.AddYears(1) < _finish)
{
_diff++;
_start = _start.AddYears(1);
}
if(_negate)
{
_diff = _diff * (-1);
}
return _diff;
}
/// <summary>
/// returns the integer number of months between start and finish
/// </summary>
/// <param name="start">Start DateTime</param>
/// <param name="finish">Finish DateTime</param>
/// <returns></returns>
public static int MonthDiff(DateTime start, DateTime finish)
{
DateTime _start, _finish;
bool _negate = (finish < start);
if (_negate)
{
_start = finish;
_finish = start;
}
else
{
_start = start;
_finish = finish;
}
int _diff = 0;
while (_start.AddMonths(1) < _finish)
{
_diff++;
_start = _start.AddMonths(1);
}
if (_negate)
{
_diff = _diff * (-1);
}
return _diff;
}
/// <summary>
/// returns the integer number of days between start and finish
/// </summary>
/// <param name="start">start DateTime</param>
/// <param name="finish">finish DateTime</param>
/// <returns></returns>
public static int DayDiff(DateTime start, DateTime finish)
{
var _diff = finish - start;
return (int)_diff.TotalDays;
}
/// <summary>
/// returns the integer number of hours between start and finish
/// </summary>
/// <param name="start">start DateTime</param>
/// <param name="finish">finish DateTime</param>
/// <returns></returns>
public static int HourDiff(DateTime start, DateTime finish)
{
var _diff = finish - start;
return(int)_diff.TotalHours;
}
/// <summary>
/// returns the integer number of minutes between start and finish
/// </summary>
/// <param name="start">start DateTime</param>
/// <param name="finish">finish DateTime</param>
/// <returns></returns>
public static int MinuteDiff(DateTime start, DateTime finish)
{
var _diff = finish - start;
return (int)_diff.TotalMinutes;
}
/// <summary>
/// returns the integer number of seconds between start and finish
/// </summary>
/// <param name="start">start DateTime</param>
/// <param name="finish">finish DateTime</param>
/// <returns></returns>
public static int SecondDiff(DateTime start, DateTime finish)
{
var _diff = finish - start;
return (int)_diff.TotalSeconds;
}
/// <summary>
/// returns the integer number of milliseconds between start and finish
/// </summary>
/// <param name="start">start DateTime</param>
/// <param name="finish">finish DateTime</param>
/// <returns></returns>
public static int MilliSecondDiff(DateTime start, DateTime finish)
{
var _diff = finish - start;
return (int)_diff.TotalMilliseconds;
}
/// <summary>
/// returns the integer remaining number of months between two DateTimes
/// after the year difference has been removed
/// </summary>
/// <param name="start">start DateTime</param>
/// <param name="finish">finish DateTime</param>
/// <returns></returns>
public static int MonthPartDiff(DateTime start, DateTime finish)
{
return MonthDiff(start.AddYears(YearDiff(start, finish)), finish);
}
/// <summary>
/// returns the integer remaining number of days between two DateTimes
/// after the year difference and the month difference has been removed
/// </summary>
/// <param name="start"></param>
/// <param name="finish"></param>
/// <returns></returns>
public static int DayPartDiff(DateTime start, DateTime finish)
{
return DayDiff(start.AddMonths(MonthDiff(start, finish)), finish);
}
/// <summary>
/// returns the integer remaining number of hours between two DateTimes
/// after the year, month and day difference has been removed
/// </summary>
/// <param name="start"></param>
/// <param name="finish"></param>
/// <returns></returns>
public static int HourPartDiff(DateTime start, DateTime finish)
{
return (finish-start).Hours;
}
/// <summary>
/// returns the integer remaining number of minutes between two DateTimes
/// after the year, month, day and hour difference has been removed
/// </summary>
/// <param name="start"></param>
/// <param name="finish"></param>
/// <returns></returns>
public static int MinutePartDiff(DateTime start, DateTime finish)
{
return (finish-start).Minutes;
}
/// <summary>
/// returns the integer remaining number of seconds between two DateTimes
/// after the year, month, day, hour and minute difference has been removed
/// </summary>
/// <param name="start"></param>
/// <param name="finish"></param>
/// <returns></returns>
public static int SecondPartDiff(DateTime start, DateTime finish)
{
return (finish - start).Seconds;
}
/// <summary>
/// returns the integer remaining number of milliseconds between two DateTimes
/// after the year, month, day, hour, minute and second difference has been removed
/// </summary>
/// <param name="start"></param>
/// <param name="finish"></param>
/// <returns></returns>
public static int MilliSecondPartDiff(DateTime start, DateTime finish)
{
return (finish - start).Milliseconds;
}
}
So you could call it like this:
var finish = DateTime.Now;
var start = new DateTime(1967, 7, 3);
var years = DateCalcs.YearDiff(start, finish);
Console.WriteLine ("Age in years: {0}", years);
var months = DateCalcs.MonthDiff(start, finish);
Console.WriteLine("Age in months: {0}", months);
var days = DateCalcs.DayDiff(start, finish);
Console.WriteLine("Age in days: {0}", days);
var hours = DateCalcs.HourDiff(start, finish);
Console.WriteLine("Age in hours: {0}", hours);
var minutes = DateCalcs.MinuteDiff(start, finish);
Console.WriteLine("Age in minutes: {0}", minutes);
var seconds = DateCalcs.SecondDiff(start, finish);
Console.WriteLine("Age in seconds: {0}", seconds);
var milliSeconds = DateCalcs.MilliSecondDiff(start, finish);
Console.WriteLine("Age in milliseconds: {0}", milliSeconds);
var AgeString = string.Format("{0}yr, {1}mo, {2}d, {3}h, {4}m, {5}s, {6}ms",
DateCalcs.YearDiff(start, finish),
DateCalcs.MonthPartDiff(start, finish),
DateCalcs.DayPartDiff(start, finish),
DateCalcs.HourPartDiff(start, finish),
DateCalcs.MinutePartDiff(start, finish),
DateCalcs.SecondPartDiff(start, finish),
DateCalcs.MilliSecondPartDiff(start, finish)
);
Console.WriteLine("Or {0}", AgeString);
Which just now returned
Age in years: 46
Age in months: 560
Age in days: 17073
Age in hours: 409771
Age in minutes: 24586290
Age in seconds: 1475177401
Age in milliseconds: -2147483648
Or 46yr, 8mo, 28d, 19h, 30m, 1s, 792ms
精彩评论