So, when I initially posed the programming challenge #1 I stated:
… since I intended to output HTML, ASP.NET seemed a logical choice. But I was amazed at the amount of code required for such a seemingly simple task (not to mention how ugly code containing
<%and%>is!).
Well, it turns out, using plain old C# with a little LINQ to XML functional construction made my solution a lot nicer.
Prerequisites
I created a few DateTimeExtensions to enhance readability, though I could have easily inlined the implementation of each of those methods without any LOC impact.
public static class DateTimeExtensions { public static DateTime ToFirstDayOfMonth(this DateTime dt) { return new DateTime(dt.Year, dt.Month, 1); } public static DateTime ToLastDayOfMonth(this DateTime dt) { return new DateTime(dt.Year, dt.Month, DateTime.DaysInMonth(dt.Year, dt.Month)); } public static DateTime ToFirstDayOfWeek(this DateTime dt) { return dt.AddDays(-((int) dt.DayOfWeek)); } public static DateTime ToLastDayOfWeek(this DateTime dt) { return dt.AddDays(6 - ((int) dt.DayOfWeek)); } }
I also relied on the Slice extension method I’ve previously blogged about.
Solution
static void Main(string[] args) { DateTime today = DateTime.Today; DateTime firstDayOfMonth = today.ToFirstDayOfMonth(); DateTime startCalendar = firstDayOfMonth.ToFirstDayOfWeek(); DateTime lastDayOfMonth = today.ToLastDayOfMonth(); DateTime endCalendar = lastDayOfMonth.ToLastDayOfWeek(); var calendarPrefix = from day in Enumerable.Range(startCalendar.Day, (firstDayOfMonth - startCalendar).Days) select new XElement("td", new XAttribute("class", "prevMonth"), day); var calendarMonth = from day in Enumerable.Range(1, lastDayOfMonth.Day) select new XElement("td", day == today.Day ? new XAttribute("class", "today") : null, day); var calendarSuffix = from day in Enumerable.Range(1, (endCalendar - lastDayOfMonth).Days) select new XElement("td", new XAttribute("class", "nextMonth"), day); var calendar = calendarPrefix.Concat(calendarMonth).Concat(calendarSuffix); var table = new XElement("table", new XElement("thead", new XElement("tr", from offset in Enumerable.Range(0, 7) select new XElement("th", startCalendar.AddDays(offset).ToString("ddd")))), new XElement("tbody", from week in calendar.Slice(7) select new XElement("tr", week))); Console.WriteLine(table); }
I’d love to see more ways to solve this. If you’ve got a simpler or more beautiful implementation in your favorite programming langauge/web application framework, let me know in the comments of the original post.
[...] I posted my solution at http://jacobcarpenter.wordpress.com/2008/04/16/pc1-a-solution/. [...]
Pingback by Programming Challenge #1: HTML calendar « Jacob Carpenter’s Weblog — April 16, 2008 @ 12:24 pm
Very elegant.
Comment by Will Asrari — April 16, 2008 @ 12:39 pm