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 !
Moonshield
March 27, 2009, March 27, 2009 01:00, permalink
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();
}
}
}
mannu.myopenid.com
March 27, 2009, March 27, 2009 11:37, permalink
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... :)
mannu.myopenid.com
March 27, 2009, March 27, 2009 12:09, permalink
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;
}
Jared
May 3, 2009, May 03, 2009 06:46, permalink
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;
}
}
}
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"