55502f40dc8b7c769880b10874abc9d0

Hi all,

I've made a method which I am not proud of. I tremble upon the thought of changed requirements. It should take a list of DateTimes and present it in chronological order, grouping dates in days if they have the same time, according to the examples below.

It works now but I am very curious to see if there is (which I am sure there is) a better way to do this.

Thanks! :)

"Mar 3-6 13:00, Mar 10-13 13:00, Mar 17-20 13:00, Mar 24-27 13:00, Mar 31 13:00, Apr 1-3 13:00, Apr 7-8 13:00, Apr 14-17 13:00"

And

"Mar 14 13:00, Mar 16 09:30, Mar 16 10:45, Mar 17 09:30, Mar 17 10:45, Mar 18 09:30, Mar 18 10:45, Mar 19 09:30, Mar 19 10:45, Mar 20 09:30, Mar 20 10:45, Mar 21 13:00, Mar 23 09:30, Mar 23 10:45, Mar 24 09:30, Mar 24 10:45, Mar 25 09:30, Mar 25 10:45, Mar 26 09:30, Mar 26 10:45, Mar 27 09:30, Mar 27 10:45, Mar 28 13:00"

private string GetDateString(List<DateTime> dates)
        {
            StringBuilder sb = new StringBuilder();

            if (dates.Count == 1)
            {
                sb.Append(string.Format(CultureInfo.InvariantCulture, "{0:MMM} ", dates[0]));
                sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}{1} {2:HH:mm}", dates[0].Day, GetYearString(dates[0]), dates[0]));

                return sb.ToString();
            }

            dates.Sort();

            for (int i = 0; i <= dates.Count - 1; i++)
            {
                if (i == 0)
                {
                    sb.Append(string.Format(CultureInfo.InvariantCulture, "{0:MMM} ", dates[0]));
                    sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}", dates[0].Day));

                    if (i < dates.Count - 1)
                    {
                        if (dates[i + 1].DayOfYear != dates[i].DayOfYear + 1)
                        {
                            sb.Append(string.Format(CultureInfo.InvariantCulture, "{0} {1:HH:mm}, ", GetYearString(dates[i]), dates[i]));
                        }
                    }

                    continue;
                }
                else if (i == 1 && dates[i].DayOfYear - 1 == dates[i - 1].DayOfYear)
                {
                }
                else
                {
                    sb.Append(string.Format(CultureInfo.InvariantCulture, "{0:MMM} ", dates[i]));
                }

                if (i < dates.Count - 1)
                {
                    if ((dates[i].DayOfYear + 1) != dates[i + 1].DayOfYear &&
                        dates[i].Month == dates[i + 1].Month &&
                        dates[i].Year == dates[i + 1].Year &&
                        dates[i].TimeOfDay == dates[i + 1].TimeOfDay)
                    {
                        if (i > 1)
                        {
                            sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}{1} {2:HH:mm}, ", dates[i].Day, GetYearString(dates[i]), dates[i]));
                        }

                        continue;
                    }
                }

                bool stepDates = true;

                if (i != dates.Count - 1)
                {
                    while (dates[i].DayOfYear + 1 == (dates[i + 1].DayOfYear) &&
                        dates[i].TimeOfDay == dates[i + 1].TimeOfDay &&
                        dates[i].Month == dates[i + 1].Month &&
                        dates[i].Year == dates[i + 1].Year)
                    {
                        if (stepDates)
                        {
                            if (i > 1)
                            {
                                sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}", dates[i].Day));
                            }

                            stepDates = false;

                            sb.Append("-");
                        }

                        i++;

                        if ((i == dates.Count - 1) ||
                            (dates[i].DayOfYear + 1 != dates[i + 1].DayOfYear &&
                            dates[i].Year == dates[i + 1].Year))
                        {
                            break;
                        }
                    }
                }

                sb.Append(string.Format(CultureInfo.InvariantCulture, "{0}{1} {2:HH:mm}, ", dates[i].Day, GetYearString(dates[i]), dates[i]));
            }

            return sb.ToString().Substring(0, sb.Length - 2);
        }

        private string GetYearString(DateTime inputDate)
        {
            if (inputDate.Year != DateTime.Now.Year)
            {
                return string.Format(" {0}", inputDate.Year);
            }

            return string.Empty;
        }

Refactorings

No refactoring yet !

72f36daa501cf8f5bb861210edd9232d

Moonshield

March 27, 2009, March 27, 2009 01:00, permalink

No rating. Login to rate!

Probably not perfect but you have the main idea and you can modify it to your needs.
I suggest to use the StringBuilder.AppendFormat method instead StringBuilder.Append(string.format("",something)), it's too much overhead :)

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime oDate = DateTime.Now;
            List<DateTime> aDate = new List<DateTime>()
            {
                oDate.AddHours(1),
                oDate,
                oDate.AddDays(10),
                oDate.AddYears(-1),
                oDate.AddDays(-10),
                oDate.AddYears(2)
            };

            string Result = Program.GetDateString(aDate);
            foreach (string Date in Result.Split(','))
                Console.WriteLine(Date.Trim());

            Console.ReadLine();
        }

        private static string GetDateString(List<DateTime> paDate)
        {
            StringBuilder oSb = new StringBuilder();

            if (paDate != null && paDate.Count > 0)
            {
                int CurrentYear = int.MinValue;

                paDate.Sort();
                paDate.ForEach(oDate =>
                {
                    if (oDate.Year != CurrentYear)
                    {
                        CurrentYear = oDate.Year;
                        oSb.AppendFormat(CultureInfo.InvariantCulture, "{0:MMM dd yyyy HH:mm}, ", oDate);
                    }
                    else
                        oSb.AppendFormat(CultureInfo.InvariantCulture, "{0:MMM dd HH:mm}, ", oDate);
                });

                if (oSb.Length > 2)
                    oSb.Remove(oSb.Length - 2, 2);
            }

            return oSb.ToString();
        }
    }
}
55502f40dc8b7c769880b10874abc9d0

mannu.myopenid.com

March 27, 2009, March 27, 2009 11:37, permalink

No rating. Login to rate!

Nice! There is one problem though. If you have May 12, 13, 14, 15 and 16 and they are all on 15:30, it should be May 12-16 15:30... :)

55502f40dc8b7c769880b10874abc9d0

mannu.myopenid.com

March 27, 2009, March 27, 2009 12:09, permalink

No rating. Login to rate!

I came up with this now. No idea if I can make it smaller.

private string GetDateString(List<DateTime> dates)
        {
            if (dates.Count == 1)
            {
                return string.Format(CultureInfo.InvariantCulture, "{0:MMM dd HH:mm}", dates[0]);
            }

            StringBuilder sb = new StringBuilder();

            dates.Sort();

            for (int i = 0; i <= dates.Count - 1; i++)
            {
                if (i == dates.Count - 1)
                {
                    if (dates[i - 1].DayOfYear == dates[i].DayOfYear - 1 &&
                        dates[i - 1].Year == dates[i].Year)
                    {
                        if (dates[i - 1].TimeOfDay == dates[i].TimeOfDay &&
                            dates[i - 1].DayOfYear == dates[i].DayOfYear - 1)
                        {
                            sb.AppendFormat(CultureInfo.InvariantCulture, "{0:dd HH:mm}, ", dates[i]);
                        }
                        else
                        {
                            sb.AppendFormat(CultureInfo.InvariantCulture, "{0:MMM dd HH:mm} ", dates[i]);
                        }
                    }
                    else
                    {
                        sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} {2:HH:mm}, ", dates[i].Day, GetYearString(dates[i]), dates[i]);
                    }
                }

                sb.AppendFormat(CultureInfo.InvariantCulture, "{0:MMM} ", dates[i]);
                sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", dates[i].Day, GetYearString(dates[i]));

                bool stepDates = true;

                while (i != dates.Count - 1 &&
                    dates[i + 1].DayOfYear == dates[i].DayOfYear + 1 &&
                    dates[i + 1].Year == dates[i].Year)
                {
                    if (stepDates)
                    {
                        sb.Append("-");

                        stepDates = false;
                    }

                    i++;
                }

                if (stepDates)
                {
                    sb.AppendFormat(" {0:HH:mm}, ", dates[i]);
                }
                else
                {
                    sb.AppendFormat(CultureInfo.InvariantCulture, "{0}{1} {2:HH:mm}, ", dates[i].Day, GetYearString(dates[i]), dates[i]);
                }
            }

            if (sb.Length > 2)
            {
                return sb.ToString().Substring(0, sb.Length - 2);
            }

            return string.Empty;
        }
2c6eb400022df8462362756dfd8dbbf5

Jared

May 3, 2009, May 03, 2009 06:46, permalink

No rating. Login to rate!

It makes more sense to me to think about it as a conversion from dates to vectors. I am sure it could be made more efficient.

using System;
using System.Collections.Generic;
using System.Text;

namespace RefactorMyCode
{
    class Program
    {
        static void Main(string[] args)
        {
            var da = new List<DateTime>();
            da.Add(new DateTime(2000, 1, 1, 12, 0, 0));
            da.Add(new DateTime(2000, 1, 3, 12, 0, 0));
            da.Add(new DateTime(2000, 1, 2, 12, 0, 0));
            da.Add(new DateTime(2000, 1, 2, 11, 0, 0));
            da.Add(new DateTime(2000, 1, 3, 12, 0, 0));
            da.Add(new DateTime(2000, 1, 5, 12, 0, 0));

            string result = GetDateString(da);
        }

        private static string GetDateString(List<DateTime> collection)
        {
            StringBuilder sb = new StringBuilder();

            collection.Sort();
            DateVector[] dates = DateVector.Convert(collection);
            string[] dateStrings = Array.ConvertAll(dates, item => item.ToString());

            return string.Join(", ", dateStrings);
        }

    }

    class DateVector
    {
        DateTime Date;
        int Length = 0;

        public DateVector() { }
        public DateVector(DateTime date, int length)
        {
            this.Date = date;
            this.Length = length;
        }

        public override string ToString()
        {
            string result = string.Empty;

            if (this.Length > -1)
            {
                string duration = (this.Length > 0) ? duration = "-" + (this.Date.Day + this.Length) : string.Empty;
                string year = (this.Date.Year != DateTime.Now.Year) ? this.Date.Year.ToString() + " " : string.Empty;
                result = this.Date.ToString("MMM d{0} {1}H:mm");
                result = string.Format(result, duration, year);
            }
            
            return result;
        }

        public static DateVector[] Convert(List<DateTime> collection)
        {
            int[] durations = new int[collection.Count];

            //Calculate date durations
            for (int i = 1; i < collection.Count; i++)
            {
                int index = GetRootDateIndex(collection, durations, i);
                if (index != i)
                {
                    durations[i] = -1;
                    //If it is not a duplicate date
                    if (collection[i].Day > collection[index].Day + durations[index])
                    {
                        durations[index]++;
                    }
                }
            }

            //Convert to DateVectors
            List<DateVector> result = new List<DateVector>(collection.Count);
            for (int i = 0; i < collection.Count; i++)
            {
                if (durations[i] > -1) result.Add(new DateVector(collection[i], durations[i]));
            }
            return result.ToArray();
        }

        /// <summary>
        /// Gets the index of the first date in a series, with contiguous dates and duplicate times, from a specified date in the series.
        /// </summary>
        /// <param name="collection">The sorted collection of dates.</param>
        /// <param name="durations">The current durations.</param>
        /// <param name="current">The index of the date of interest.</param>
        /// <returns></returns>
        private static int GetRootDateIndex(List<DateTime> collection, int[] durations, int current)
        {
            if (collection.Count == 0 || current == 0) return 0;
            int result = current;

            DateTime currentDate = collection[current];

            for (int i = current - 1; i >= 0; i--)
            {
                DateTime previous = currentDate.Date.AddDays(-1);
                if (collection[i].Date == previous
                    && collection[i].TimeOfDay == currentDate.TimeOfDay)
                {
                    if (durations[i] > -1)
                    {
                        result = i;
                        break;
                    }
                    currentDate = collection[i];
                }
                if (collection[i].Date < previous) break;
            }

            return result;
        }
    }
}

Your refactoring





Format Copy from initial code

or Cancel