C#中两个日期之间的周差异

3
我将尝试在C#中编写一个函数,用于返回两个日期之间的周差异。其目标是提供与以下相同的结果:
select datediff(ww,'2018-04-13','2018-04-16') as diff

在上面的例子中,这两个日期之间仅相差3天,但它们属于不同的周,因此结果应该是1。
我尝试使用.TotalDays,但它不能正确工作。我还尝试使用.GetWeekOfYear,但当日期的年份不同时,它无法正确返回。我在StackOverflow和其他论坛上看到了很多类似的问题,但目前为止没有一个与我的情况匹配。这是我正在尝试的函数:
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;

}

在我的函数的第一部分,我尝试了这篇文章中描述的方法。但它没有起作用。
你能帮我吗? 提前致谢。

有什么问题吗?只需检查年份,如果它们不同,则将所有周的总数相加,并将其添加到差值中。 - johnny 5
可能是此问题的重复:计算两个日期时间之间周数最有效的方法 - Leustherin
1
@Leustherin 有部分重叠,但是这里的 OP 想要在周日到周一(相隔1天)时返回1周,在同一周的周六到周日则返回0周。稍微有些变化。 - Chrᴉz remembers Monica
2
你可以计算每个日期的一周开始日期,然后获取TotalDays并除以7并向上取整。你需要确定你认为的一周开始日期,并确定如果第二个日期在第一个日期之前应该返回什么。 - sgmoore
请问您能否提供更多的测试用例和期望结果? - Dan Wilson
@AndréLuiz,带错误的答案解决了您的问题吗?我发布了另一个按您要求正确工作的答案。 - Chrᴉz remembers Monica
6个回答

4

首先计算两个日期之间的天数,然后将天数除以7得到整周数。

接着找出是否有额外的一周需要计算,方法是用天数对7取余数得到剩余天数。如果第一个日期加上剩余天数落在另一个星期,就将计数器加一周。

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;
}

你的解决方案也可行。我正在使用它,因为你允许设置一周的开始。 - André Luiz

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));
}

首先,将日期设置为当前周的星期一。然后计算所有完整的周数(即/7天作为整数)。这很简单,它可能适用于跨越周和年份。


1

看看这是否有效。可能还有更多使用情况没有涵盖,解决方案取决于如何定义一周的边界(这假设基于上面的评论是以星期日至星期一为基础)。

// 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;
}

不能处理同一周内的两个不同日期,此情况应返回0。 - sgmoore
@DanWilson感谢您的回答!我尝试了一下,进行了一些测试,目前看来它似乎可以正常工作。 - André Luiz
@DanWilson 仍然无法正确处理同一周内的日期 2018年4月13日和2018年4月14日之间的周数:1 - phuzi
很抱歉,我失败了。:( - Dan Wilson

0

或许它可以帮助

    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);
    }

获取给定日期的正确周数


0

虽然我还不能发表评论,并且已经在此帖子上使用了一个标记,因为我相信它和某个东西很相似。这里是另一篇我找到的帖子,看起来与你正在尝试创建的解决方案相符:

在C#中获取两个日期之间的日历周数


0

这是我解决类似问题的实现方式,虽然我还没有进行充分测试,但看起来可以正常工作。

        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;

如果间隔小于等于6天,它会返回1周,这正是我所需要的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接