One way to do this is to use a class to represent your dates, and implement IComparable
on the class. This allows you to customize the sorting algorithm so that B.C. dates are sorted in reverse order (compared to A.D. dates).
Below I've created a class that has properties for the year, month, day, along with a bool that is set to false
for B.C. dates. I added a Parse()
method that can take one of your example strings (without the "event" part) and return an BCADDate
object. It would be trivial to add an "event" property and the ability to parse the event from the string as well, if needed (comment below and I can add it).
Basically the comparison works like:
- If the dates do not have the same BC/AD designation, then the BC one comes first
- Otherwise, compare the years, then the months, and then the days, and return the result of the comparison of first one that doesn't match. Reverse the result for BC dates by multiplying it by
-1
- Return
0
if all the properties match
Edit
I added the implementation of the IComparer
interface also, in case that helps for using this with the treeview.
Here's the code:
class BCADDate : IComparable, IComparer
{
public int Year { get; set; }
public int Month { get; set; }
public int Day { get; set; }
public bool IsAD { get; set; }
public static BCADDate Parse(string input)
{
var result = new BCADDate();
if (string.IsNullOrWhiteSpace(input))
throw new ArgumentException("input cannot be null, empty, or whitespace");
var dateADParts = input.Split(' ');
var dateParts = dateADParts[0].Split('/');
if (dateParts.Length < 3)
throw new FormatException(
"The string must have three parts separated by the '/' character.");
try
{
result.Year = int.Parse(dateParts[0]);
result.Month = int.Parse(dateParts[1]);
result.Day = int.Parse(dateParts[2]);
}
catch
{
throw new FormatException(
"All parts of the date portion must be valid integers.");
}
result.IsAD = (dateADParts.Length == 1)
? true // A.D. is true if nothing is specified
: dateADParts[1].IndexOf("A", StringComparison.OrdinalIgnoreCase) > -1;
return result;
}
public int CompareTo(object obj)
{
var other = obj as BCADDate;
if (other == null) return 1;
var BCMultiplier = IsAD ? 1 : -1;
// Use default comparers for our fields
if (this.IsAD != other.IsAD)
return this.IsAD.CompareTo(other.IsAD);
if (this.Year != other.Year)
return this.Year.CompareTo(other.Year) * BCMultiplier;
if (this.Month != other.Month)
return this.Month.CompareTo(other.Month) * BCMultiplier;
if (this.Day != other.Day)
return this.Day.CompareTo(other.Day) * BCMultiplier;
return 0;
}
public int Compare(object x, object y)
{
var first = x as BCADDate;
var second = y as BCADDate;
if (first == null) return second == null ? 0 : -1;
return first.CompareTo(second);
}
public override string ToString()
{
var bcad = IsAD ? "A.D." : "B.C.";
return $"{Year:0000}/{Month:00}/{Day:00} {bcad}";
}
}
Here's an example of the usage:
var dates = new List<BCADDate>
{
BCADDate.Parse("0123/05/05 B.C."),
BCADDate.Parse("2015/01/01 A.D."),
BCADDate.Parse("2017/01/21 A.D."),
BCADDate.Parse("2125/12/05 B.C.")
};
Console.WriteLine("Original ordering:");
dates.ForEach(Console.WriteLine);
dates.Sort();
Console.WriteLine("------------------");
Console.WriteLine("Sorted ordering:");
dates.ForEach(Console.WriteLine);
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
Output
