Subscribe to Sergio Tapia - Lost in the GC.        RSS Feed
-----

Getting the business days in a month using C#.

Icon 7 Comments
So in my application, I found myself needing a way to get business days for a given month. It's for student attendance, so I only need to get the days from Monday through Friday for a given month.

Hopefully someone finds this useful. :)

//Monday to Friday are business days.
var weekends = new DayOfWeek[] { DayOfWeek.Saturday, DayOfWeek.Sunday };

//Represents January.
int month = 1; 
int year = 2011; 

//Fetch the amount of days in your given month.
int daysInMonth = DateTime.DaysInMonth(year, month);

//Here we create and enumerable from 1 to daysInMonth,
//and ask whether the DateTime object we create belongs to a weekend day,
//if it doesn't, add it to our IEnumerable<int> collection of days.
IEnumerable<int> businessDaysInMonth = Enumerable.Range(1, daysInMonth)
                                       .Where(d => !weekends.Contains(new DateTime(year, month, d).DayOfWeek));

//Pretty smooth. :)
foreach (var day in businessDaysInMonth)
{
    Console.WriteLine(day);
}



If you can make this even better, please share! We can all learn. :)

Here's something you can just drop into a Console Application to see how fast it runs. Make sure to add a using declartion for System.Diagnostics.

Stopwatch stopwatch = Stopwatch.StartNew();

//Monday to Friday are business days.
var weekends = new DayOfWeek[] { DayOfWeek.Saturday, DayOfWeek.Sunday };

//Represents January.
int month = 1; 
int year = 2011; 

//Fetch the amount of days in your given month.
int daysInMonth = DateTime.DaysInMonth(year, month);

//Here we create and enumerable from 1 to daysInMonth,
//and ask whether the DateTime object we create belongs to a weekend day,
//if it doesn't, add it to our IEnumerable<int> collection of days.
IEnumerable<int> businessDaysInMonth = Enumerable.Range(1, daysInMonth)
                                        .Where(d => !weekends.Contains(new DateTime(year, month, d).DayOfWeek));

//Pretty smooth. :)
foreach (var day in businessDaysInMonth)
{
    Console.WriteLine(day);
}

stopwatch.Stop();
Console.WriteLine("Time elapsed: {0} ms.", stopwatch.ElapsedMilliseconds);
Console.ReadKey(true);

7 Comments On This Entry

Page 1 of 1

Raynes Icon

28 May 2011 - 12:40 PM
Nice. I don't know if you've realized it, but your example is fairly functional code. You're creating new instances of things rather than mutating them, and you're iterating through collections instead of using for loops and the like. I know you're interested in Clojure, so here is how I would implement this in Clojure:

(ns business-days.core
  (:refer-clojure :exclude [extend])
  (:use clj-time.core))

(defn business-days [year month]
  (count
   (for [day (range 1 (-> (date-time year month)
                          .dayOfMonth
                          .getMaximumValue
                          inc))
         :let [new-date (date-time year month day)]
         :when (> 6 (.getDayOfWeek new-date))]
     day)))



I'm using clj-time which is a wrapper around joda-time. Unfortunately, clj-time doesn't wrap most of what I needed here, so I ended up calling out to the joda API directly, but that wasn't any trouble at all, as you can see. My implementation is very similar to yours. Note that in Clojure, 'for' isn't a for loop, but is a list comprehension. Wikipedia can be helpful if you don't know what that is.

Here is an example of its usage:

Quote

user=> (business-days 2011 5)
22
user=> (business-days 2011 6)
22
user=> (business-days 2011 7)
21


If you just want a list of all the business days in the month (and not just the number of them), you can just remove the call to count in the code. If I were providing this function as part of an API, I'd do that, because it's more useful to have a list of all the days than to have the number of them, and it's easy to derive the number of them from the list (by calling count).

Happy hacking!
1

Nakor Icon

28 May 2011 - 11:53 PM
Here's a similar version to yours but put into a DateTime extension method so you can call it on any DateTime object to get the business days for that dates month/year
    public static class DateTimeExtension
    {
        public static IEnumerable<int> BusinessDays(this DateTime date)
        {
            var days = (from d in DaysInMonth(date)
                        let day = new DateTime(date.Year, date.Month, d).DayOfWeek
                        where 
                            day != DayOfWeek.Saturday 
                            && day != DayOfWeek.Sunday
                        select d);
            return days;
        }

        private static IEnumerable<int> DaysInMonth(DateTime date)
        {
            return Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month));
        }
    }

1

Nakor Icon

28 May 2011 - 11:57 PM
And example of use, though it's probably pretty obvious to someone who's familiar with extension methods...

            DateTime today = DateTime.Today;

            foreach (var day in today.BusinessDays())
            {
                Console.WriteLine(day);
            }

0

Nakor Icon

29 May 2011 - 12:12 AM
For some reason I can't edit previous posts, anyways, after a little thought I thought it might be better to return actual DateTime values for the business days

    public static class DateTimeExtension
    {
        public static IEnumerable<DateTime> BusinessDays(this DateTime date)
        {
            return (from d in DaysInMonth(date)
                    let day = new DateTime(date.Year, date.Month, d).DayOfWeek
                    where
                        day != DayOfWeek.Saturday
                        && day != DayOfWeek.Sunday
                    select (new DateTime(date.Year, date.Month, d)));
        }

        private static IEnumerable<int> DaysInMonth(DateTime date)
        {
            return Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month));
        }
    }



Then you can still do this to get just the days

            DateTime today = DateTime.Today;

            foreach (var day in today.BusinessDays())
            {
                Console.WriteLine(day.Day.ToString());
            }



Or you could do this to get the date of each of the days

            foreach (var day in today.BusinessDays())
            {
                Console.WriteLine(day.ToShortDateString());
            }

1

Sergio Tapia Icon

29 May 2011 - 06:22 AM
Thanks for sharing guys! That's some pretty crispy code you have there. :)
0

Knld Icon

10 June 2011 - 08:42 AM
Thank You

Where does the "d" in line 17 of the first code block come from?

.Where(d =>

Whats the meaning?
0

Sergio Tapia Icon

10 June 2011 - 08:53 AM
The 'd' is just an identifier I used. I could have named it 'cheese' or 'blue' or 'skyline'. What's happening is I'm iterating through each object in the collection Enumerable.Range() and referencing each item by the identifier 'd' inside of the Where clause ONLY.
0
Page 1 of 1

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

2 user(s) viewing

2 Guests
0 member(s)
0 anonymous member(s)

About Me

Posted Image


Bienvenidos! I'm a USA ex-pat living in Bolivia for the past 10 years. Web development is my forte with a heavy lean for usability and optimization. I'm fluent in both English and Spanish. I guest write for the popular Python website Python Central. Visit my website.

Categories