# DateTime Span

S

#### shapper

Hello,

I am trying to get the span between two dates in seconds, minutes,
hours, weeks, months or years.

I came up with the following:

public static Int64 Span(DateTime begin, DateTime end,
TimeInterval interval) {

// Check inputs
if (begin > end) throw new ArgumentException("Begin date must be
previous or equal to end date");

// Define count
TimeSpan span = end - begin;
switch (interval) {
case TimeInterval.Year:
return (Int64)(end.Year - begin.Year);
case TimeInterval.Month:
return (Int64)((end.Month - begin.Month) + (12 * (end.Year -
begin.Year)));
case TimeInterval.Week:
return (Int64)Math.Floor(span.TotalDays) / 7;
case TimeInterval.Day:
return (Int64)Math.Floor(span.TotalDays);
case TimeInterval.Hour:
return (Int64)Math.Floor(span.TotalHours);
case TimeInterval.Minute:
return (Int64)Math.Floor(span.TotalMinutes);
case TimeInterval.Second:
return (Int64)Math.Floor(span.TotalSeconds);
default:
return (Int64)span.Ticks;
}

} // Span

For example, in months, I was trying to get the following rule:
The difference between 2010-20-01 and 2010-18-02 is 0 months.
The difference between 2010-20-01 and 2010-20-02 is 1 month.

So it becomes only 1 month if the day of the end date is after the day
of the being date.
Does this make sense? How can I do this?

I am not sure if I can make other improvements to my code ... But any
suggestion is welcome.

Thank You,
Miguel

P

#### Peter Duniho

shapper said:
Hello,

I am trying to get the span between two dates in seconds, minutes,
hours, weeks, months or years.
[...]
For example, in months, I was trying to get the following rule:
The difference between 2010-20-01 and 2010-18-02 is 0 months.
The difference between 2010-20-01 and 2010-20-02 is 1 month.

So it becomes only 1 month if the day of the end date is after the day
of the being date.
Does this make sense? How can I do this?

If you want the equivalent to "TotalMonths" and "TotalYears" (had those
been present in the TimeSpan structure), you'll need specific knowledge
of the calendar, which TimeSpan doesn't have (which is also why it
doesn't have those two properties).

In particular, because each month is a different number of days, the
only way to calculate total months is to literally enumerate each month
from the start and end dates, subtracting the total days of each month
as you go until you run out of days, incrementing your month counter as
you go.

Once you have total months, the total years is easier. You still need
to know you calendar, but almost everyone is using a 12-month calendar
so as a limited hack, you can just divide by 12.

So, how do you get the number of days for each month? See:
http://msdn.microsoft.com/en-us/library/system.globalization.calendar.getdaysinmonth.aspx

If you want to go beyond the limited hack of dividing by 12, there's
also a method to retrieve the number of months in a year for a given
calendar:
http://msdn.microsoft.com/en-us/library/system.globalization.calendar.getmonthsinyear.aspx

Finally, I will point out that a method that does N different things
depending on an argument is usually not the best design. In fact, you
can see this rule exemplified in the various time-related classes.
Rather than having the caller pass an argument that the method then
needs to switch on, just make a different method name for each operation
you want to accomplish. Then the caller can just call the appropriate
method.

Pete

J

#### Jeff Johnson

The difference between 2010-20-01 and 2010-18-02 is 0 months.
The difference between 2010-20-01 and 2010-20-02 is 1 month.

Where do you live that yyyy-dd-mm is a valid date string...?

G

shapper said:
I am trying to get the span between two dates in seconds, minutes,
hours, weeks, months or years.

Add a reference to the Miscrosoft.VisualBasic.dll library, and use the
DateDiff method.

Yes, I know, there is a lot of evil in there, but there is no reason to
reimplement something that is easily available.

S

#### shapper

Add a reference to the Miscrosoft.VisualBasic.dll library, and use the
DateDiff method.

Yes, I know, there is a lot of evil in there, but there is no reason to
reimplement something that is easily available.

Sorry for the delay ...
And is it possible to get the DateDiff code and change it to C# ...
Well, just wondering ...

S

#### shapper

Add a reference to the Miscrosoft.VisualBasic.dll library, and use the
DateDiff method.

Yes, I know, there is a lot of evil in there, but there is no reason to
reimplement something that is easily available.

A similar version of the code in C# is:

using System;
using System.Collections.Generic;
using System.Text;

namespace datediffdemo
{
public enum DateInterval
{
Day,
DayOfYear,
Hour,
Minute,
Month,
Quarter,
Second,
Weekday,
WeekOfYear,
Year
}

public class DateAndTime
{
public static long DateDiff(DateInterval interval, DateTime
dt1, DateTime dt2)
{
return DateDiff(interval, dt1, dt2,
System.Globalization.DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek);
}

private static int GetQuarter(int nMonth)
{
if (nMonth <= 3)
return 1;
if (nMonth <= 6)
return 2;
if (nMonth <= 9)
return 3;
return 4;
}

public static long DateDiff(DateInterval interval, DateTime
dt1, DateTime dt2, DayOfWeek eFirstDayOfWeek)
{
if (interval == DateInterval.Year)
return dt2.Year - dt1.Year;

if (interval == DateInterval.Month)
return (dt2.Month - dt1.Month) + (12 * (dt2.Year -
dt1.Year));

TimeSpan ts = dt2 - dt1;

if (interval == DateInterval.Day || interval ==
DateInterval.DayOfYear)
return Round(ts.TotalDays);

if (interval == DateInterval.Hour)
return Round(ts.TotalHours);

if (interval == DateInterval.Minute)
return Round(ts.TotalMinutes);

if (interval == DateInterval.Second)
return Round(ts.TotalSeconds);

if (interval == DateInterval.Weekday )
{
return Round(ts.TotalDays / 7.0);
}

if (interval == DateInterval.WeekOfYear)
{
while (dt2.DayOfWeek != eFirstDayOfWeek)
while (dt1.DayOfWeek != eFirstDayOfWeek)
ts = dt2 - dt1;
return Round(ts.TotalDays / 7.0);
}

if (interval == DateInterval.Quarter)
{
double d1Quarter = GetQuarter(dt1.Month);
double d2Quarter = GetQuarter(dt2.Month);
double d1 = d2Quarter - d1Quarter;
double d2 = (4 * (dt2.Year - dt1.Year));
return Round(d1 + d2);
}

return 0;

}

private static long Round(double dVal)
{
if (dVal >= 0)
return (long)Math.Floor(dVal);
return (long)Math.Ceiling(dVal);
}
}
}

But is missing the FirstDayOfWeek functionality ... which is part of
DateDiff:
http://msdn.microsoft.com/en-us/library/b5xbyt6f(VS.71).aspx

Strange that there isn't this in C# ...

Z

#### zooots

Hi,you can try this.

case TimeInterval.Week:
return (Int64)Math.Floor(span.FromDays) / 7;
case TimeInterval.Day:
return (Int64)Math.Floor(span.FromDays);
case TimeInterval.Hour:
return (Int64)Math.Floor(span.FromHours);
case TimeInterval.Minute:
return (Int64)Math.Floor(span.FromMinutes);
case TimeInterval.Second:
return (Int64)Math.Floor(span.FromSeconds);