tags:

views:

611

answers:

4

Hi

Can anyone tell me how to calculate the diff between two dates without using .net datetime and timestamp classes?

Thanks

+2  A: 

If you can't use a DateTime, what do you have? Strings? In that case, use one of the DateTime.Parse() variants* or Convert.ToDateTime() and do the comparison there. That's the only correct way. Anything else and we'll need a little more info.

* DateTime.Parse(), DateTime.TryParse(), DateTime.ParseExact(), or DateTime.TryParseExact().

Joel Coehoorn
+1  A: 

Based on the comment, I choose that the date-time be stored as number of clock cycles since Jan 1, 1901. Now, it's a matter of simply subtracting one from the other, dividing by clock cycles per second, and further dividing by the coefficient appropriate to the unit of time you want measured (60 for minutes, 3600 for hours, 3600 * 24 for days, etc.)

Jekke
Clock cycles feels like overkill to me - you'd need to consider time zones and all kinds of oddities. Given that we've only got *dates*, why not store it as the number of *days* since a particular date?
Jon Skeet
I don't see why I'd have to consider time zones. The advantage of count-based date-time systems is that they are completely clock and calendar independent and know the difference between, for example, the first 2 AM and the second 2 AM on clock-back day. (Clock cycles is an extreme example, but one used in real-world OSs.)
Jekke
+3  A: 

If I couldn't use the built-in types, I'd try to find another .NET date/time API. I suspect I wouldn't find one though, given that any sane person would use the built-in ones.

If it's really just a case of dates, I guess a full date/time API isn't really required. Parse whatever you get into "days since some epoch" (e.g. Jan 1st 1970) and just do normal subtraction.

Be careful of leap years though - and things get even more fun if you need to cope with the bizarre calendar changes a few centuries back.

Sample code assuming a format of "yyyyMMdd", not doing any error checking, not coping with dates before 1900, and not worrying about efficiency at all:

using System;

struct Date
{
    readonly int year;
    readonly int month;
    readonly int day;

    public Date(int year, int month, int day)
    {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public static Date Parse(string text)
    {
        return new Date(int.Parse(text.Substring(0, 4)),
                        int.Parse(text.Substring(4, 2)),
                        int.Parse(text.Substring(6, 2)));
    }

    // Days since first Jan 1st 1900
    public int DaysSinceEpoch
    {
        get
        {
            int days = 0;
            for (int i = 1900; i < year; i++)
            {
                days += IsLeapYear(i) ? 366 : 365;
            }
            for (int i = 1; i < month; i++)
            {
                days += GetMonthLength(i, year);
            }
            days += day - 1;
            return days;
        }
    }

    private static readonly int[] MonthLengths = 
    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    private static int GetMonthLength(int month, int year)
    {
        return MonthLengths[month-1] + 
            ((IsLeapYear(year) && month == 2) ? 1 : 0);
    }

    private static bool IsLeapYear(int year)
    {
        // http://en.wikipedia.org/wiki/Leap_year
        if ((year % 4) != 0) return false;
        if ((year % 400) == 0) return true;
        if ((year % 100) == 0) return false;
        return true;
    }
}

class Test
{
    static void Main(string[] args)
    {
        Console.WriteLine(DateDiff("19040301", "19050301")); // 365
        Console.WriteLine(DateDiff("19040201", "19050201")); // 366
        Console.WriteLine(DateDiff("19760619", "20090529")); // I feel old
    }

    static int DateDiff(string first, string second)
    {
        Date firstDate = Date.Parse(first);
        Date secondDate = Date.Parse(second);
        return secondDate.DaysSinceEpoch - firstDate.DaysSinceEpoch;
    }
}
Jon Skeet
Sure, just parse out the date and time, do the math, take into consideration leap years, etc... Hey, someone should really build an API for this. Maybe it should even be included in .NET!
Jon B
Well yes indeed... it makes a bit more sense as a "puzzle" type problem in an interview though, in terms of "can this developer think through the corner cases and write usable code".
Jon Skeet
This line here " if ((year % 400) == 0) return true; " was bugging the crap out of me... I wrote a quick test harness very similar to yours but was coming out 2 days out of sync with what the DateTime-DateTime version was giving me
Eoin Campbell
@Eoin: Do you mean you believe it to be wrong, or you believe it to be right but it represents a rule you didn't know about before?
Jon Skeet
Nah I believe it to be right :) I just hadn't checked wikipedia and as a result, my code was slightly off ;)
Eoin Campbell
I also assume the .NET DateTime object has been returning correct values also ;-)
Eoin Campbell
+1  A: 

I'll bet the person interviewing you was a VB dev, and expected you to answer with use the builtin VB datediff function (Microsoft.VisualBasic.DateAndTime.DateDiff). I'm not 100% but I believe that function has an overload for string or object date arguments.

James