tags:

views:

60

answers:

2

What library can I use to calculate dates based on date expressions?

A date expression would be something like:

  • "+3D" (plus three days)
  • "-1W" (minus one week)
  • "-2Y+2D+1M" (minus 2 years, plus one day, plus one month)

Example:

DateTime EstimatedArrivalDate = CalcDate("+3D", DateTime.Now);

Where estimated arrival date would equal the current date plus 3 days.

I have heard about JodaTime and NodaTime but I have not seen anything in them yet that does this. What should I be using to get this functionality in C#?

+3  A: 

There is no library (that I'm aware of, including the port of JodaTime to .NET) that will work with expressions like this. As long as the expressions are simply chained (as they are in your example), it should be pretty easy to write a RegEx to parse that expression and do the processing yourself:

public static DateTime CalcDate(string expression, DateTime epoch)
{
    var match = System.Text.RegularExpressions.Regex.Match(expression, 
                    @"(([+-])(\d+)([YDM]))+");

    if (match.Success && match.Groups.Count >= 5)
    {
        var signs = match.Groups[2];
        var counts = match.Groups[3];
        var units = match.Groups[4];

        for (int i = 0; i < signs.Captures.Count; i++)
        {
            string sign = signs.Captures[i].Value;
            int count = int.Parse(counts.Captures[i].Value);
            string unit = units.Captures[i].Value;

            if (sign == "-") count *= -1;

            switch (unit)
            {
                case "Y": epoch = epoch.AddYears(count); break;
                case "M": epoch = epoch.AddMonths(count); break;
                case "D": epoch = epoch.AddDays(count); break;
            }
        }
    }
    else
    {
        throw new FormatException(
            "The specified expression was not a valid date expression.");
    }

    return epoch;
}
Adam Robinson
Downvoter care to comment...?
Adam Robinson
Wow, that is awesome. Can you explain what the match.Groups.Count >= 5 is for?
ObligatoryMoniker
The first group is the main outer expression (-2Y+2D+1M), which we don't want. The second will be the individual items (-2Y, +2D, and +1M), which we also don't want. The third, fourth, and fifth groups represent the individual captures for sign, count, and unit. The `>=5` is just there to ensure that we don't access an index that's out of bounds.
Adam Robinson
+2  A: 

You can use combinations of DateTime and TimeSpan to do all that. You can find some good example at http://dotnetperls.com/timespan

From your example: DateTime EstimatedArrivalDate = DateTime.Now.AddDays(3);

CuriousCoder
Just FYI, the `TimeSpan` structure can't be used here; neither year nor month are fixed units of measure. (In other words, the actual length of time can vary from one month or one year to another).
Adam Robinson