Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#
Tip/Trick

Converting Days of the Week to and from a BitFlag

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
7 Oct 2011CPOL 14.4K   2  
A utility class that lets you store a set of days of the week in a single int value

I thought I'd share this bit of code with you. It's basically a way of converting the System.DayOfWeek enum into a bitfield enum. Because I'm working on a transit database, I need a column that lets me store specific combinations of days, like Monday to Friday, or Saturday and Sunday. I'd like to translate those combinations into ints and back into combinations. So here's the utility class to do it:


C#
public static class DaysOfWeekUtils
{
    #region Nested Enums
    [Flags]
    private enum DayOfWeekBitFlag
    {
        Sunday = 0x1,
        Monday = 0x2,
        Tuesday = 0x4,
        Wednesday = 0x8,
        Thursday = 0x10,
        Friday = 0x20,
        Saturday = 0x40
    }
    #endregion

    #region Private Fields
    private static Dictionary<DayOfWeekBitFlag, DayOfWeek> systemDayOfWeek;
    private static Dictionary<DayOfWeek, DayOfWeekBitFlag> bitFlagDayOfWeek;
    #endregion

    #region Constructors
    static DaysOfWeekUtils()
    {
        systemDayOfWeek = new Dictionary<DayOfWeekBitFlag, DayOfWeek>();
        systemDayOfWeek[DayOfWeekBitFlag.Sunday] = DayOfWeek.Sunday;
        systemDayOfWeek[DayOfWeekBitFlag.Monday] = DayOfWeek.Monday;
        systemDayOfWeek[DayOfWeekBitFlag.Tuesday] = DayOfWeek.Tuesday;
        systemDayOfWeek[DayOfWeekBitFlag.Wednesday] = DayOfWeek.Wednesday;
        systemDayOfWeek[DayOfWeekBitFlag.Thursday] = DayOfWeek.Thursday;
        systemDayOfWeek[DayOfWeekBitFlag.Friday] = DayOfWeek.Friday;
        systemDayOfWeek[DayOfWeekBitFlag.Saturday] = DayOfWeek.Saturday;

        bitFlagDayOfWeek = new Dictionary<DayOfWeek, DayOfWeekBitFlag>();
        bitFlagDayOfWeek[DayOfWeek.Sunday] = DayOfWeekBitFlag.Sunday;
        bitFlagDayOfWeek[DayOfWeek.Monday] = DayOfWeekBitFlag.Monday;
        bitFlagDayOfWeek[DayOfWeek.Tuesday] = DayOfWeekBitFlag.Tuesday;
        bitFlagDayOfWeek[DayOfWeek.Wednesday] = DayOfWeekBitFlag.Wednesday;
        bitFlagDayOfWeek[DayOfWeek.Thursday] = DayOfWeekBitFlag.Thursday;
        bitFlagDayOfWeek[DayOfWeek.Friday] = DayOfWeekBitFlag.Friday;
        bitFlagDayOfWeek[DayOfWeek.Saturday] = DayOfWeekBitFlag.Saturday;

        MondayToFridayCode = valueOf(DayOfWeek.Monday, DayOfWeek.Tuesday, 
            DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday);
    }
    #endregion

    #region Public Properties
    public static int MondayToFridayCode { get; private set; }

    public static IEnumerable<DayOfWeek> EachDayOfTheWeek
    {
        get
        {
            yield return DayOfWeek.Sunday;
            yield return DayOfWeek.Monday;
            yield return DayOfWeek.Tuesday;
            yield return DayOfWeek.Wednesday;
            yield return DayOfWeek.Thursday;
            yield return DayOfWeek.Friday;
            yield return DayOfWeek.Saturday;
        }
    }

    public static IEnumerable<DayOfWeek> MondayToFriday
    {
        get
        {
            return daysOfWeek(MondayToFridayCode);
        }
    }
    #endregion

    #region Public Methods
    public static IEnumerable<DayOfWeek> daysOfWeek(int val)
    {
        foreach (DayOfWeekBitFlag bitFlag in systemDayOfWeek.Keys)
            if ((val & (int)bitFlag) == (int)bitFlag)
                yield return systemDayOfWeek[bitFlag];
    }

    public static int valueOf(params DayOfWeek[] daysOfWeek)
    {
        return daysOfWeek.Distinct().Sum(dayOfWeek => (int)bitFlagDayOfWeek[dayOfWeek]);
    }
    #endregion
}

and here is its test class:


C#
[TestClass]
public class DayOfWeekUtilsUnitTests
{
    #region Test Methods
    [TestMethod]
    public void testDaysOfTheWeek()
    {
        // Not doing this in a nested loop just
        // in order to see the structure clearly.
        foreach (DayOfWeek[] combination in combinations(7))
            testDaysOfWeek(combination);

        foreach (DayOfWeek[] combination in combinations(6))
            testDaysOfWeek(combination);

        foreach (DayOfWeek[] combination in combinations(5))
            testDaysOfWeek(combination);

        foreach (DayOfWeek[] combination in combinations(4))
            testDaysOfWeek(combination);

        foreach (DayOfWeek[] combination in combinations(3))
            testDaysOfWeek(combination);

        foreach (DayOfWeek[] combination in combinations(2))
            testDaysOfWeek(combination);

        foreach (DayOfWeek[] combination in combinations(1))
            testDaysOfWeek(combination);
    }

    private IEnumerable<DayOfWeek[]> combinations(int arrayLength)
    {
        if (arrayLength == 0)
            yield return new DayOfWeek[0];
        else
            foreach (DayOfWeek dayOfWeek in DaysOfWeekUtils.EachDayOfTheWeek)
                foreach (DayOfWeek[] combination in combinations(arrayLength - 1))
                    yield return combination.Concat(Enumerable.Repeat(dayOfWeek, 1)).ToArray();
    }

    [TestMethod]
    public void testDaysOfTheWeekUtilsProperty()
    {
        IEnumerable<DayOfWeek> daysOfTheWeek = DaysOfWeekUtils.EachDayOfTheWeek;
        Assert.AreEqual(daysOfTheWeek.Count(), 7);
        Assert.IsTrue(daysOfTheWeek.Contains(DayOfWeek.Sunday));
        Assert.IsTrue(daysOfTheWeek.Contains(DayOfWeek.Monday));
        Assert.IsTrue(daysOfTheWeek.Contains(DayOfWeek.Tuesday));
        Assert.IsTrue(daysOfTheWeek.Contains(DayOfWeek.Wednesday));
        Assert.IsTrue(daysOfTheWeek.Contains(DayOfWeek.Thursday));
        Assert.IsTrue(daysOfTheWeek.Contains(DayOfWeek.Friday));
        Assert.IsTrue(daysOfTheWeek.Contains(DayOfWeek.Saturday));
    }

    [TestMethod]
    public void testMondayToFriday()
    {
        IEnumerable<DayOfWeek> mondayToFriday = DaysOfWeekUtils.MondayToFriday;
        Assert.IsTrue(mondayToFriday.Count() == 5);

        Assert.IsTrue(mondayToFriday.Contains(DayOfWeek.Monday));
        Assert.IsTrue(mondayToFriday.Contains(DayOfWeek.Tuesday));
        Assert.IsTrue(mondayToFriday.Contains(DayOfWeek.Wednesday));
        Assert.IsTrue(mondayToFriday.Contains(DayOfWeek.Thursday));
        Assert.IsTrue(mondayToFriday.Contains(DayOfWeek.Friday));
    }

    [TestMethod]
    public void testNonExistentDays()
    {
        IEnumerable<DayOfWeek> noDays = DaysOfWeekUtils.daysOfWeek(256);
        Assert.AreEqual(noDays.Count(), 0);
    }
    #endregion

    #region Private Methods
    private void testDaysOfWeek(params DayOfWeek[] daysOfWeek)
    {
        int val = DaysOfWeekUtils.valueOf(daysOfWeek);
        IEnumerable<DayOfWeek> computedEnumeration = DaysOfWeekUtils.daysOfWeek(val);
        Assert.AreEqual(daysOfWeek.Distinct().Count(), computedEnumeration.Count());
        foreach (DayOfWeek dayOfWeek in computedEnumeration)
            Assert.IsTrue(daysOfWeek.Contains(dayOfWeek));
    }
    #endregion
}

To convert an int into an IEnumerable<DayOfWeek>, use the daysOfWeek() method; to go the other way, use the valueOf() method. I've included ModayToFriday and ModayToFridayCode shortcuts; feel free to add your own as and when the need arises.


Enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) SpiegelSoft
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --