views:

278

answers:

5

Does anyone know of a good piece of C# code or assembly that supports the following:

  1. Find the 1st Tuesday of June 2012
  2. Find the last Friday of March 2008
  3. Find every Saturday in January 2013
  4. Find the 3rd Friday in July 2009
  5. Find every Saturday over the next 3 months
  6. Find every day in March 2018

The results should come back as DateTime and/or List<DateTime>.

Of course, as you can imagine, I'm looking to create a scheduler.

A: 

Yes, the .NET Framework will support that without any problems ;)

But seriously - you should be able to write code that does that fairly easily. If not, ask a question when you get stuck, and we'll help out. But you won't need any external assemblies - just go with a standard C# class =)

Tomas Lycken
Why are you down-voting this people? The question is homework, don't give the OP the answer, help him/her get there.
Martin
How does this answer help the OP get there?
bzlm
bzlm: The OP clearly believes (or used to) that creating code for this is so hard that there migth be some external assembly that does this for him/her. As it is not (unless you have extreme performance requirements, it can be done fairly easily) and the OP doesn't seem to have even tried on his/her own, and as it is tagged "Homework", just giving away some code that does the job doesn't really seem to help either.
Tomas Lycken
+1  A: 

Here is an example on how to do the first day of a month.

public enum Month
{
    January = 1,
    Febuary = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12
}

public static Nullable<DateTime> FindTheFirstDayOfAMonth(DayOfWeek dayOfWeek, Month month, int year)
{
    // Do checking of parameters here, i.e. year being in future not past

    // Create a DateTime object the first day of that month
    DateTime currentDate = new DateTime(year, (int)month, 1);

    while (currentDate.Month == (int)month)
    {
        if (currentDate.DayOfWeek == dayOfWeek)
        {
            return currentDate;
        }

        currentDate = currentDate.AddDays(1);
    }

    return null;
}

You call it like

Nullable<DateTime> date = Program.FindTheFirstDayOfAMonth(DayOfWeek.Monday, Month.September, 2009);

So you get the idea. You will have to do various functions do get what you want to achieve.

David Basarab
A: 

When I wrote a scheduler I pretty much copied SQL Servers sysschedules table

http://msdn.microsoft.com/en-us/library/ms178644.aspx

Using things like Frequency Type, Frequency Interval, etc... really made it easy to compute the values in code, but I am guessing there is a sproc to do it for you. I am searching for that now.

Bob
How's the searching going?
bzlm
+3  A: 

Here are methods to find the first/last specified day of week in a given month:

public DateTime GetFirstDayOfWeekInMonth(int year, int month, DayOfWeek dayOfWeek)
{
    DateTime dt = new DateTime(year, month, 1);
    int first = (int)dt.DayOfWeek;
    int wanted = (int)dayOfWeek;
    if (wanted < first)
        wanted += 7;
    return dt.AddDays(wanted - first);
}

public DateTime GetLastDayOfWeekInMonth(int year, int month, DayOfWeek dayOfWeek)
{
    int daysInMonth = CultureInfo.CurrentCulture.Calendar.GetDaysInMonth(year, month);
    DateTime dt = new DateTime(year, month, daysInMonth);
    int last = (int)dt.DayOfWeek;
    int wanted = (int)dayOfWeek;
    if (wanted > last)
        last += 7;
    return dt.AddDays(wanted - last);
}

From those, you can easily find the answers to the other questions... just add 7 days to find the next occurence of the day you're looking for


EDIT: thinking more about it, it would be pretty handy to have that in the form of extension methods, such as :

Console.WriteLine("Next monday : {0}", DateTime.Today.Next(DayOfWeek.Monday));
Console.WriteLine("Last saturday : {0}", DateTime.Today.Previous(DayOfWeek.Saturday));

Here is the implementation :

public static class DateExtensions
{
    public static DateTime Next(this DateTime from, DayOfWeek dayOfWeek)
    {
        int start = (int)from.DayOfWeek;
        int wanted = (int)dayOfWeek;
        if (wanted < start)
            wanted += 7;
        return from.AddDays(wanted - start);
    }

    public static DateTime Previous(this DateTime from, DayOfWeek dayOfWeek)
    {
        int end = (int)from.DayOfWeek;
        int wanted = (int)dayOfWeek;
        if (wanted > end)
            end += 7;
        return from.AddDays(wanted - end);
    }
}

It's probably more flexible than the first methods I suggested... With that, you can easily do things like that :

// Print all Sundays between 2009/01/01 and 2009/03/31
DateTime from = new DateTime(2009, 1, 1);
DateTime to = new DateTime(2009, 3, 31);
DateTime sunday = from.Next(DayOfWeek.Sunday);
while(sunday <= to)
{
   Console.WriteLine(sunday);
   sunday = sunday.AddDays(7);
}
Thomas Levesque
A: 

Inspired by this question it seemed like a fun thing to make something that allows you to treat dates as sequences and query them with LINQ. I've made a simple project that can be downloaded here from GitHub. Don't know if it was necessary to add it to source control as I doubt I'll be working on it, but had to upload it somewhere and uploading it to RapidShare seemed a little dodgy :)

Your first questions solved with my "Linq-to-DateTime":

  /*
   *    1. Find the 1st Tuesday of June 2012
        2. Find the last Friday of March 2008
        3. Find every Saturday in January 2013
        4. Find the 3rd Friday in July 2009
        5. Find every Saturday over the next 3 months
        6. Find every day in March 2018
  */

  var firstTuesday = (from d in DateSequence.FromYear(2012).June()
                    where d.DayOfWeek == DayOfWeek.Tuesday
                    select d).First();

  var lastFriday = (from d in DateSequence.FromYear(2008).March()
                    where d.DayOfWeek == DayOfWeek.Friday
                    select d).Last();

  var saturdays = (from d in DateSequence.FromYear(2013).January()
                   where d.DayOfWeek == DayOfWeek.Saturday
                   select d);

  var thirdFriday = (from d in DateSequence.FromYear(2009).July()
                     where d.DayOfWeek == DayOfWeek.Friday
                     select d).Skip(2).First();

  var nextSaturdays = (from d in DateSequence.FromDates(DateTime.Today, DateTime.Today.AddMonths(3))
                       where d.DayOfWeek == DayOfWeek.Saturday
                       select d);

  var allDays = (from d in DateSequence.FromYear(2018).March()
                 select d);

Not shown in this example is that you can choose the granularity of your queries. Meaning that if you do this:

  var days = (from d in DateSequence.FromYears(2001, 2090).AsYears()
              where d.Year % 2 == 0
              select d.Year).ToList();

You will iterate through the dates with an increment of a year. The default is AsDays() if you don't specify anything.

The project is pretty barebone, no commentary or unit tests, but I hope this can still help you. If not, then it was fun writing anyway :)

JulianR