Get Elapsed Time as Human Friendly String In lieu with several other Facebook-esque concepts I am trying to replicate, this working code will take the span of time from a given date to now, and try to convert it into the most convenient English-friendly word. For example, if I post a comment on an article or status, and I want to show when it was posted to a user who views it, it would indicate something like "5 minutes ago", versus a date itself.

Concerns: Does this cover all possible use cases? Is it done optimally in the least lines of code?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Schloss.Text
{
    public static class Date
    {
        public static string GetElapsedTime(DateTimeOffset datetime)
        {
            TimeSpan ts = DateTimeOffset.Now.Subtract(datetime);

            int years = ts.Days / 365;
            int months = ts.Days / 30;
            int weeks = ts.Days / 52;

            if (years == 1) // one year ago
                return "A year ago";

            if (years &gt; 1) // greater than one year
            {
                if (ts.Days % 365 == 0) // even year
                    return (int)(ts.TotalDays / 365) + " years ago";
                else // not really entire years
                    return "About " + (int)(ts.TotalDays / 365) + " years ago";
            }

            if (months == 1) // one month
                return "About a month ago";

            if (months &gt; 1) // more than one month
                return "About " + months + " months ago";

            if (weeks == 1) // a week ago
                return "About a week ago";

            if (weeks &gt; 1) // more than a week ago, but less than a month ago
                return "About " + weeks + " weeks ago";

            if (ts.Days == 1) // one day ago
                return "Yesterday";

            if (ts.Days &gt; 1) //  more than one day ago, but less than one week ago
                return ts.Days + " days ago";

            if (ts.Hours == 1) // An hour ago
                return "About an hour ago";

            if (ts.Hours &gt; 1 &amp;&amp; ts.Hours &lt;= 24) // More than an hour ago, but less than a day ago
                return "About " + ts.Hours + " hours ago";

            if (ts.Minutes == 1)
                return "About a minute ago";

            if (ts.Minutes == 0)
                return ts.Seconds + " seconds ago";

            return ts.Minutes + " minutes ago";
        }
    }
}
Does this cover all possible use cases?


Maybe, but it doesn't calculate timespan components (year, month, etc) exactly.


  Is it done optimally in the least lines of code?


Probably no.
You could generalize check of different TimeSpan elements using the following approach:

private static string GetElapsedTime(DateTime datetime)
{
    TimeSpan ts = DateTime.Now.Subtract(datetime);

    // The trick: make variable contain date and time representing the desired timespan,
    // having +1 in each date component.
    DateTime date = DateTime.MinValue + ts;

    return ProcessPeriod(date.Year - 1, date.Month - 1, "year")
           ?? ProcessPeriod(date.Month - 1, date.Day - 1, "month")
           ?? ProcessPeriod(date.Day - 1, date.Hour, "day", "Yesterday")
           ?? ProcessPeriod(date.Hour, date.Minute, "hour")
           ?? ProcessPeriod(date.Minute, date.Second, "minute")
           ?? ProcessPeriod(date.Second, 0, "second")
           ?? "Right now";
}

private static string ProcessPeriod(int value, int subValue, string name, string singularName = null)
{
    if (value == 0)
    {
        return null;
    }
    if (value == 1)
    {
        if (!String.IsNullOrEmpty(singularName))
        {
            return singularName;
        }
        string articleSuffix = name[0] == 'h' ? "n" : String.Empty;
        return subValue == 0
            ? String.Format("A{0} {1} ago", articleSuffix, name)
            : String.Format("About a{0} {1} ago", articleSuffix, name);
    }
    return subValue == 0
        ? String.Format("{0} {1}s ago", value, name)
        : String.Format("About {0} {1}s ago", value, name);
}