Как проверить, находится ли DateTime между 2 днями недели (DayOfWeek) - PullRequest
11 голосов
/ 27 октября 2010

В C # при произвольном наборе конечных точек DayOfWeek (например, DayOfWeek.Friday и DayOfWeek.Sunday) как будет один тест, если произвольная дата попадает между этими двумя днями включительно?

Пример:

// result == true; Oct 23, 2010 is a Saturday
var result = InBetweenDaysInclusive(new DateTime(2010, 10, 23),
                                    DayOfWeek.Friday,
                                    DayOfWeek.Sunday);

// result == true; Oct 22, 2010 is a Friday
result = InBetweenDaysInclusive(new DateTime(2010, 10, 22),
                                DayOfWeek.Friday,
                                DayOfWeek.Sunday);

// result == true; Oct 24, 2010 is a Sunday
result = InBetweenDaysInclusive(new DateTime(2010, 10, 24),
                                DayOfWeek.Friday,
                                DayOfWeek.Sunday);

// result == false; Oct 25, 2010 is a Monday
result = InBetweenDaysInclusive(new DateTime(2010, 10, 25),
                                DayOfWeek.Friday,
                                DayOfWeek.Sunday);

Спасибо!

Ответы [ 6 ]

13 голосов
/ 27 октября 2010

Эта функция будет нуждаться в двух отдельных ветвях в зависимости от того, является ли разница между начальной и конечной датой отрицательной или положительной / нулевой.

Я мог бы быть совершенно неосновным, но я думаю, что это работает для всех случаев:

// No state in method, so made it static
public static bool InBetweenDaysInclusive(DateTime date, DayOfWeek start, DayOfWeek end)
{
    DayOfWeek curDay = date.DayOfWeek;

    if (start <= end)
    {
        // Test one range: start to end
        return (start <= curDay && curDay <= end);
    }
    else
    {
        // Test two ranges: start to 6, 0 to end
        return (start <= curDay || curDay <= end);
    }
}

Для справки, ваши тестовые данные вернули следующее, когда я запустил их и добавил Console.WriteLine для каждого результата:

True
True
True
False

Редактировать: мое последнее объяснение было слишком расплывчатым. Вот фиксированный.

Хитрость в том, что если end < start, то у вас есть два допустимых диапазона: start до верхней границы и нижняя граница до end. Это приведет к (start <= curDay && curDay <= upperBound) || curDay <= end && lowerBound <= curDay)

Однако, поскольку они ограничены, curDay - это всегда <= upperBound и >= lowerBound, поэтому мы опускаем этот код.

7 голосов
/ 27 октября 2010

Каждая дата попадает между любыми двумя заданными днями недели (подумайте об этом) ...

Вам необходимо получить даты конечной точки для дня dayOfWeek, ближайшего к дате ввопрос (где разность дней <7).Затем вы делаете простое сравнение. </p>


ПРИМЕЧАНИЕ: следующее решение предполагает, что неделя - с воскресенья по субботу

Учитывая следующие методы расширения:

    /// <summary>
    /// Gets the date of the next occurrence of the day of week provided
    /// </summary>
    /// <param name="value"></param>
    /// <param name="nextDay"></param>
    /// <returns></returns>
    public static DateTime NextOccurance(this DateTime value, DayOfWeek nextDay)
    {
        if (value.DayOfWeek == nextDay) { return value; }
        else if (value.DayOfWeek > nextDay) { return value.AddDays(7 - (value.DayOfWeek - nextDay)); }
        else { return value.AddDays(nextDay - value.DayOfWeek); }
    }

    /// <summary>
    /// Gets the date of the last occurrence of the day of week provided
    /// </summary>
    /// <param name="value"></param>
    /// <param name="lastDay"></param>
    /// <returns></returns>
    public static DateTime LastOccurance(this DateTime value, DayOfWeek lastDay)
    {
        if (value.DayOfWeek == lastDay) { return value; }
        else if (value.DayOfWeek > lastDay) { return value.AddDays(-(value.DayOfWeek - lastDay)); }
        else { return value.AddDays((lastDay - value.DayOfWeek) - 7); }
    }

    /// <summary>
    /// Gets the date of the closest occurrence of the day of week provided
    /// </summary>
    /// <param name="value"></param>
    /// <param name="day"></param>
    /// <returns></returns>
    public static DateTime ClosestOccurance(this DateTime value, DayOfWeek day)
    {
        DateTime before = value.LastOccurance(day);
        DateTime after = value.NextOccurance(day);
        return ((value - before) < (after - value))
            ? before
            : after;
    }

Вы можете узнать, попадает ли рассматриваемый день в две даты, например: (эта часть предполагает неделю).С воскресенья по субботу)

DayOfWeek dayOne = DayOfWeek.Tuesday;
DayOfWeek dayTwo = DayOfWeek.Friday;
DateTime doesDateFallWithin = DateTime.Today;
bool fallsWithin =
   doesDateFallWithin.ClosestOccurance(dayOne) <= doesDateFallWithin
   && doesDateFallWithin <= doesDateFallWithin.ClosestOccurance(dayTwo);

Мои результаты:

dayOne = пятница, dayTwo = вторник

10/27/2010 (Wednesday) does not fall within the closest occurrences of Friday (10/29/2010) and Tuesday (10/26/2010)
10/28/2010 (Thursday) does not fall within the closest occurrences of Friday (10/29/2010) and Tuesday (10/26/2010)
10/29/2010 (Friday) does not fall within the closest occurrences of Friday (10/29/2010) and Tuesday (10/26/2010)
10/30/2010 (Saturday) falls within the closest occurrences of Friday (10/29/2010) and Tuesday (11/2/2010)
10/31/2010 (Sunday) falls within the closest occurrences of Friday (10/29/2010) and Tuesday (11/2/2010)
11/1/2010 (Monday) falls within the closest occurrences of Friday (10/29/2010) and Tuesday (11/2/2010)
11/2/2010 (Tuesday) does not fall within the closest occurrences of Friday (11/5/2010) and Tuesday (11/2/2010)
11/3/2010 (Wednesday) does not fall within the closest occurrences of Friday (11/5/2010) and Tuesday (11/2/2010) 

dayOne = понедельник, dayTwo = среда

10/27/2010 (Wednesday) falls within the closest occurrences of Monday (10/25/2010) and Wednesday (10/27/2010)
10/28/2010 (Thursday) does not fall within the closest occurrences of Monday (10/25/2010) and Wednesday (10/27/2010)
10/29/2010 (Friday) does not fall within the closest occurrences of Monday (11/1/2010) and Wednesday (10/27/2010)
10/30/2010 (Saturday) does not fall within the closest occurrences of Monday (11/1/2010) and Wednesday (10/27/2010)
10/31/2010 (Sunday) does not fall within the closest occurrences of Monday (11/1/2010) and Wednesday (11/3/2010)
11/1/2010 (Monday) falls within the closest occurrences of Monday (11/1/2010) and Wednesday (11/3/2010)
11/2/2010 (Tuesday) falls within the closest occurrences of Monday (11/1/2010) and Wednesday (11/3/2010)
11/3/2010 (Wednesday) falls within the closest occurrences of Monday (11/1/2010) and Wednesday (11/3/2010) 
5 голосов
/ 27 октября 2010

@ Указание Брэда о том, что любой день недели попадает между любыми двумя днями недели, является действительным.Тем не менее, мы предполагаем, что два дня данной недели заказаны .

То есть, когда мы говорим, "это 30 октября 2010 г. (суббота) между пятницей и воскресеньем?" , мы действительно спрашиваем, "это 30 октября 2010 г.пятница, суббота или воскресенье? ".

Это наблюдение позволяет нам разбить проблему на две составляющие и легко решить ее полностью:

1) Определитьесли определенный день недели является одним из определенного набора дней недели (это тривиально).

2) Определите набор дней недели, которые переносят вас от одного дня к другому.То есть нам нужна функция, которая возвращает «пятница, суббота, воскресенье», когда ей присваивается «пятница» и «воскресенье», и эта функция возвращает «понедельник, вторник, среда, четверг, пятница», когда ей дают «понедельник» и «пятница».Это сложная часть проблемы.

Чтобы решить вторую проблему, мы в основном переходим с первого дня на второй, возвращая все промежуточные дни.Чтобы сделать это правильно, мы должны учитывать тот факт, что второй день может быть меньше первого дня (в репрезентативном смысле воскресенье = 0 меньше пятницы = 5).Итак, мы выполняем «прогулку» в целочисленном пространстве и добавляем 7 ко второму дню, если он меньше первого дня.Мы преобразовываем в число дней недели (то есть целые числа по модулю 7) на «выходе».

Ниже приведен код и серия тестов, которые решают эту проблему.Метод «GetDaysBetweenInclusive» решает проблему № 2, а «IsDayOfWeekBetween» добавляет решение проблемы № 1 и решает проблему ОП.

Наслаждайтесь.

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

namespace DayOfWeekUtilities
{
    public static class DayOfWeekHelpers
    {
        /// <summary>
        /// returns all days of the week, inclusive, from day1 to day2
        /// </summary>
        public static IEnumerable<DayOfWeek> GetDaysBetweenInclusive(DayOfWeek day1,
                                                                     DayOfWeek day2)
        {
            var final = (int)day2;
            if(day2 < day1)
            {
                final += 7;
            }
            var curr = (int)day1;
            do
            {
                yield return (DayOfWeek) (curr%7);
                curr++;
            } while (curr <= final);
        }

        /// <summary>
        /// returns true if the provided date falls on a day of the 
        /// week between day1 and day2, inclusive
        /// </summary>
        public static bool IsDayOfWeekBetween(this DateTime date,
                                              DayOfWeek day1,
                                              DayOfWeek day2)
        {
            return GetDaysBetweenInclusive(day1, day2).Contains(date.DayOfWeek);
        }
    }

    [TestFixture]
    public class Tests
    {
        [Test]
        public void Test()
        {
            Assert.IsTrue(new DateTime(2010, 10, 22).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));
            Assert.IsTrue(new DateTime(2010, 10, 23).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));
            Assert.IsTrue(new DateTime(2010, 10, 24).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));
            Assert.IsFalse(new DateTime(2010, 10, 25).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));
            Assert.IsFalse(new DateTime(2010, 10, 26).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));
            Assert.IsFalse(new DateTime(2010, 10, 27).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));
            Assert.IsFalse(new DateTime(2010, 10, 28).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));
            Assert.IsTrue(new DateTime(2010, 10, 29).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Sunday));

            Assert.IsTrue(new DateTime(2010, 10, 22).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 23).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 24).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 25).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 26).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 27).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 28).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));
            Assert.IsTrue(new DateTime(2010, 10, 29).IsDayOfWeekBetween(DayOfWeek.Friday, DayOfWeek.Friday));

            Assert.IsTrue(new DateTime(2010, 10, 22).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 23).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));
            Assert.IsFalse(new DateTime(2010, 10, 24).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));
            Assert.IsTrue(new DateTime(2010, 10, 25).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));
            Assert.IsTrue(new DateTime(2010, 10, 26).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));
            Assert.IsTrue(new DateTime(2010, 10, 27).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));
            Assert.IsTrue(new DateTime(2010, 10, 28).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));
            Assert.IsTrue(new DateTime(2010, 10, 29).IsDayOfWeekBetween(DayOfWeek.Monday, DayOfWeek.Friday));

            Assert.IsTrue(new DateTime(2010, 10, 22).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
            Assert.IsTrue(new DateTime(2010, 10, 23).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
            Assert.IsTrue(new DateTime(2010, 10, 24).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
            Assert.IsTrue(new DateTime(2010, 10, 25).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
            Assert.IsTrue(new DateTime(2010, 10, 26).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
            Assert.IsFalse(new DateTime(2010, 10, 27).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
            Assert.IsTrue(new DateTime(2010, 10, 28).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
            Assert.IsTrue(new DateTime(2010, 10, 29).IsDayOfWeekBetween(DayOfWeek.Thursday, DayOfWeek.Tuesday));
        }
    }
}
0 голосов
/ 12 мая 2011

Стюарт Лауге говорит: ... выполнить "прогулку" в целочисленном пространстве.Я понимаю:

private bool InBetweenDaysInclusive(DateTime date, DayOfWeek day1, DayOfWeek day2)
{
    int d1 = (int)day1;
    int d2 = (int)day2;
    int dx = (int)date.DayOfWeek;
    if (d2 < d1) d2 += 7;
    if (dx < d1) dx += 7;
    return (dx >= d1 && dx <= d2);
}
0 голосов
/ 27 октября 2010

Я думаю, что это должно работать. Он также должен работать независимо от того, что вы считаете первым днем ​​недели:

private bool InBetweenDaysInclusive(DateTime dateToCheck, DayOfWeek lowerLimit, DayOfWeek upperLimit)
{
    CultureInfo ci = CultureInfo.CurrentCulture;

    int diffDateToCheckFirstDayOfWeek = dateToCheck.DayOfWeek - ci.DateTimeFormat.FirstDayOfWeek;
    if (diffDateToCheckFirstDayOfWeek < 0)
        diffDateToCheckFirstDayOfWeek += 7;

    int diffLowerLimitFirstDayOfWeek = lowerLimit - ci.DateTimeFormat.FirstDayOfWeek;
    if (diffLowerLimitFirstDayOfWeek < 0)
        diffLowerLimitFirstDayOfWeek += 7;

    int diffUpperLimitFirstDayOfWeek = upperLimit - ci.DateTimeFormat.FirstDayOfWeek;
    if (diffUpperLimitFirstDayOfWeek < 0)
        diffUpperLimitFirstDayOfWeek += 7;

    if (diffUpperLimitFirstDayOfWeek < diffLowerLimitFirstDayOfWeek)
        throw new Exception("The lower-limit day must be earlier in the week than the upper-limit day");

    return diffDateToCheckFirstDayOfWeek >= diffLowerLimitFirstDayOfWeek && diffDateToCheckFirstDayOfWeek <= diffUpperLimitFirstDayOfWeek;
}

Edit:
В случае, если вам интересно, if < 0 и += 7 - это то, что вычитание двух дней не учитывает культуру. Код, возможно, можно сделать немного чище, но я думаю, вы поняли.

0 голосов
/ 27 октября 2010

Томас Левеск ответ здесь хорош.Помните, что DayOfWeek.Sunday - это 0, а не 6 в этом перечислении.

Это проблематично для меня, поскольку в Норвегии понедельник - первый день недели, а не воскресенье.

В этом случае, вам следует проверить, равно ли перечисление DayOfWeek.Sunday и нужно ли добавить 7 к значению, прежде чем выполнять сравнение, чтобы убедиться, что воскресенье считается правильным.

Если у вас есть воскресеньекак первый день недели, когда вы живете, это не проблема;)

...