3

I'm trying to make a function in C# that returns the week difference between two dates. Its goal is to provide the same result of:

select datediff(ww,'2018-04-13','2018-04-16') as diff

In the example above there is only 3 days between these dates, but they are in different weeks, so the result should be 1.

I've tried to use .TotalDays but it's not working properly. I also tried .GetWeekOfYear but it won't return correctly when the year of the dates are different. I've seem many questions here on StackOverflow and on other forums and so far none of them match my case. This is the function I'm trying to far:

public static int GetWeekDiff(DateTime dtStart, DateTime dtEnd) {
    // Doesn't work
    var val = ((dtEnd - dtStart).TotalDays / 7);
    val = Math.Ceiling(val);
    return Convert.ToInt32(val);

    // Doesn't work well between years
    DateTimeFormatInfo dinfo = DateTimeFormatInfo.CurrentInfo;
    var x = dinfo.Calendar.GetWeekOfYear(dtStart, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
    var y = dinfo.Calendar.GetWeekOfYear(dtEnd, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);

    return y - x;

}

In the first part of my function, I tried what is described in this post. It didn't work

Can you help me? Thanks in advance.

André Luiz
  • 6,642
  • 9
  • 55
  • 105
  • What's the issue, just check the year, if they're not the same add up all the weeks for the year's and add it to the difference – johnny 5 Apr 19 '18 at 14:55
  • Possible duplicate of [Most efficient way to count number of weeks between two datetimes](https://stackoverflow.com/questions/5893255/most-efficient-way-to-count-number-of-weeks-between-two-datetimes) – Leustherin Apr 19 '18 at 14:56
  • 1
    @Leustherin overlaps in parts, but here OP wants to return 1 week if its Sunday to Monday (1 day apart) and 0 weeks if its Saturday to Sunday in the same week. A little twist. – Chrᴉz remembers Monica Apr 19 '18 at 15:01
  • 2
    You could calculate the start of the week for each date and then get the TotalDays and divide by 7 and round up. You need to determine what you consider the start of the week and what you want to return if the second date is before the first etc. – sgmoore Apr 19 '18 at 15:11
  • Could you please provide more test cases and expected results? – Dan Wilson Apr 19 '18 at 15:13
  • @AndréLuiz Does the answer with error solve your problem? I posted another answer working correctly the way you want it. – Chrᴉz remembers Monica Apr 19 '18 at 15:36

6 Answers6

4

First figure how many days there are between the two dates. Divide the number of days by 7 to get full weeks.

Now figure out if there's an extra week to be counted by finding taking the number of days modulus 7 to get any remaining days. If the first date plus remaining days falls in a different week, add an extra week on to the count.

void Main()
{

    var first = new DateTime(2018, 04, 13);
    var second = new DateTime(2018, 04, 16);

    Console.WriteLine(weekDiff(first, second));
}

public int weekDiff(DateTime d1, DateTime d2, DayOfWeek startOfWeek = DayOfWeek.Monday)
{
    var diff = d2.Subtract(d1);

    var weeks = (int)diff.Days / 7;

    // need to check if there's an extra week to count
    var remainingDays = diff.Days % 7;
    var cal = CultureInfo.InvariantCulture.Calendar;
    var d1WeekNo = cal.GetWeekOfYear(d1, CalendarWeekRule.FirstFullWeek, startOfWeek);
    var d1PlusRemainingWeekNo = cal.GetWeekOfYear(d1.AddDays(remainingDays), CalendarWeekRule.FirstFullWeek, startOfWeek);

    if (d1WeekNo != d1PlusRemainingWeekNo)
        weeks++;

    return weeks;
}
phuzi
  • 12,078
  • 3
  • 26
  • 50
2
static void Main(string[] args)
{
    DateTime date1 = new DateTime(2018, 04, 18);
    DateTime date2 = new DateTime(2018, 04, 19);


    System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 18), new DateTime(2018, 04, 18)))); // 0
    System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 22), new DateTime(2018, 04, 23)))); // 1
    System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 16), new DateTime(2018, 04, 22)))); // 0
    System.Console.WriteLine((GetDiff(new DateTime(2018, 04, 18), new DateTime(2018, 05, 03)))); // 2
}

private static int GetDiff(DateTime date1, DateTime date2)
{
    date1 = SetDayToMonday(date1);
    date2 = SetDayToMonday(date2);

    return (int)((date2 - date1).TotalDays / 7);
}

private static DateTime SetDayToMonday(DateTime date)
{ 
    var weekDay = date.DayOfWeek;
    if (weekDay == DayOfWeek.Sunday)
        return date.AddDays(-6);
    else
        return date.AddDays(-((int)weekDay-1));
}

First, set the day to the monday of the current week. Then count all full weeks(= /7 days as int). Easy as it is, it works probably across weeks and years.

Chrᴉz remembers Monica
  • 1,829
  • 1
  • 10
  • 24
1

See if this works. There could be more use cases that this doesn't cover, and the solution depends on how you define a week boundary (this assumes Sunday-Monday based on a comment above).

// Output:
// Weeks between 12/28/2017 and 1/10/2018: 2
// Weeks between 4/13/2018 and 4/16/2018: 1
// Weeks between 4/21/2018 and 4/22/2018: 0
// Weeks between 4/22/2018 and 4/23/2018: 1

void Main()
{
    var datePairs = new List<KeyValuePair<DateTime, DateTime>>();
    datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2017, 12, 28), new DateTime(2018, 1, 10)));
    datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2018, 4, 13), new DateTime(2018, 4, 16)));
    datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2018, 4, 21), new DateTime(2018, 4, 22)));
    datePairs.Add(new KeyValuePair<DateTime, DateTime>(new DateTime(2018, 4, 22), new DateTime(2018, 4, 23)));

    foreach (var datePair in datePairs)
    {
        var string1 = datePair.Key.ToShortDateString();
        var string2 = datePair.Value.ToShortDateString();
        Console.WriteLine($"Weeks between {string1} and {string2}: {GetWeekDiff(datePair.Key, datePair.Value)}");
    }
}

public static int GetWeekDiff(DateTime dtStart, DateTime dtEnd)
{
    var totalDays = (dtEnd - dtStart).TotalDays;
    var weeks = (int)totalDays / 7;
    var hasRemainder = totalDays % 7 > 0;
    if (hasRemainder)
    {
        if (!(dtStart.DayOfWeek.Equals(DayOfWeek.Saturday) && dtEnd.DayOfWeek.Equals(DayOfWeek.Sunday)))
        {
            weeks++;
        }
    }
    return weeks;
}
Dan Wilson
  • 3,937
  • 2
  • 17
  • 27
0

Maybe it can help

    public static int GetIso8601WeekOfYear(DateTime time)
    {
        // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll 
        // be the same week# as whatever Thursday, Friday or Saturday are,
        // and we always get those right
        DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
        if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
        {
            time = time.AddDays(3);
        }

        // Return the week of our adjusted day
        return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    }

Get the correct week number of a given date

0

Can't comment yet and already used a flag on this post on something I believed to be similar. Here is another post I found that appears to align with the solution you are trying to create:

Get the number of calendar weeks between 2 dates in C#

Leustherin
  • 41
  • 2
  • 10
0

This is my implementation to solve a similar problem, I haven't tested in thoroughly but it seems to work.

        var dt1 = DateTime.Today.AddDays(-30);
        var dt2 = DateTime.Today;

        var noOfDays =(int) (dt2 - dt1).TotalDays;
        int reminder;
        var weeks = Math.DivRem(noOfDays, 7, out reminder);
        weeks = reminder > 0 ? weeks + 1 : weeks;

It returns 1 week for 6 days or less gap, which is exactly what I needed.

SANM2009
  • 1,918
  • 2
  • 12
  • 30