“Pretty” date generator












6














I have this "pretty" date string generator in C# - pass it a date and it returns a string with "5 minutes ago" or "2 weeks, 3 days ago", etc.



It's a little verbose and hogs 61 lines, and I'm wondering if I'm missing out on some nice C# features or something. What (if any) is the best way to clean up this code? Are there any cool c# features I can use here?



public static string getTimeSpan(DateTime postDate)
{
string stringy = "";
TimeSpan diff = DateTime.Now.Subtract(postDate);
double years = Math.Floor(diff.TotalDays / 365);
double weeks = Math.Floor(diff.TotalDays / 7);
double days = diff.Days;
double hours = diff.Hours + days * 24;
double minutes = diff.Minutes + hours * 60;
if (minutes <= 1) {
stringy = "Just Now";
} else if (years >= 1) {
if (years >= 2) {
stringy = years.ToString() + " years ago";
} else {
stringy = "1 year ago";
}
} else if (weeks >= 1) {
if ((days - weeks * 7) > 0) {
if ((days - weeks * 7) > 1) {
stringy = ", " + (days - weeks * 7).ToString() + " days";
} else {
stringy = ", " + (days - weeks * 7).ToString() + " day";
}
}
if (weeks >= 2) {
stringy = weeks.ToString() + " weeks" + stringy + " ago";
} else {
stringy = "1 week" + stringy + " ago";
}
} else if (days >= 1) {
if ((hours - days * 24) > 0) {
if ((hours - days * 24) > 1) {
stringy = ", " + (hours - days * 24).ToString() + " hours";
} else {
stringy = ", " + (hours - days * 24).ToString() + " hour";
}
}
if (days >= 2) {
stringy = days.ToString() + " days" + stringy + " ago";
} else {
stringy = "1 day" + stringy + " ago";
}
} else if (hours >= 1) {
if ((minutes - hours * 60) > 0) {
if ((minutes - hours * 60) > 1) {
stringy = ", " + (minutes - hours * 60).ToString() + " minutes";
} else {
stringy = ", " + (minutes - hours * 60).ToString() + " minute";
}
}
if (hours >= 2) {
stringy = hours.ToString() + " hours" + stringy + " ago";
} else {
stringy = "1 hour" + stringy + " ago";
}
} else if (minutes > 1) {
stringy = minutes.ToString() + " minutes ago";
}
return stringy;
}









share|improve this question





























    6














    I have this "pretty" date string generator in C# - pass it a date and it returns a string with "5 minutes ago" or "2 weeks, 3 days ago", etc.



    It's a little verbose and hogs 61 lines, and I'm wondering if I'm missing out on some nice C# features or something. What (if any) is the best way to clean up this code? Are there any cool c# features I can use here?



    public static string getTimeSpan(DateTime postDate)
    {
    string stringy = "";
    TimeSpan diff = DateTime.Now.Subtract(postDate);
    double years = Math.Floor(diff.TotalDays / 365);
    double weeks = Math.Floor(diff.TotalDays / 7);
    double days = diff.Days;
    double hours = diff.Hours + days * 24;
    double minutes = diff.Minutes + hours * 60;
    if (minutes <= 1) {
    stringy = "Just Now";
    } else if (years >= 1) {
    if (years >= 2) {
    stringy = years.ToString() + " years ago";
    } else {
    stringy = "1 year ago";
    }
    } else if (weeks >= 1) {
    if ((days - weeks * 7) > 0) {
    if ((days - weeks * 7) > 1) {
    stringy = ", " + (days - weeks * 7).ToString() + " days";
    } else {
    stringy = ", " + (days - weeks * 7).ToString() + " day";
    }
    }
    if (weeks >= 2) {
    stringy = weeks.ToString() + " weeks" + stringy + " ago";
    } else {
    stringy = "1 week" + stringy + " ago";
    }
    } else if (days >= 1) {
    if ((hours - days * 24) > 0) {
    if ((hours - days * 24) > 1) {
    stringy = ", " + (hours - days * 24).ToString() + " hours";
    } else {
    stringy = ", " + (hours - days * 24).ToString() + " hour";
    }
    }
    if (days >= 2) {
    stringy = days.ToString() + " days" + stringy + " ago";
    } else {
    stringy = "1 day" + stringy + " ago";
    }
    } else if (hours >= 1) {
    if ((minutes - hours * 60) > 0) {
    if ((minutes - hours * 60) > 1) {
    stringy = ", " + (minutes - hours * 60).ToString() + " minutes";
    } else {
    stringy = ", " + (minutes - hours * 60).ToString() + " minute";
    }
    }
    if (hours >= 2) {
    stringy = hours.ToString() + " hours" + stringy + " ago";
    } else {
    stringy = "1 hour" + stringy + " ago";
    }
    } else if (minutes > 1) {
    stringy = minutes.ToString() + " minutes ago";
    }
    return stringy;
    }









    share|improve this question



























      6












      6








      6


      1





      I have this "pretty" date string generator in C# - pass it a date and it returns a string with "5 minutes ago" or "2 weeks, 3 days ago", etc.



      It's a little verbose and hogs 61 lines, and I'm wondering if I'm missing out on some nice C# features or something. What (if any) is the best way to clean up this code? Are there any cool c# features I can use here?



      public static string getTimeSpan(DateTime postDate)
      {
      string stringy = "";
      TimeSpan diff = DateTime.Now.Subtract(postDate);
      double years = Math.Floor(diff.TotalDays / 365);
      double weeks = Math.Floor(diff.TotalDays / 7);
      double days = diff.Days;
      double hours = diff.Hours + days * 24;
      double minutes = diff.Minutes + hours * 60;
      if (minutes <= 1) {
      stringy = "Just Now";
      } else if (years >= 1) {
      if (years >= 2) {
      stringy = years.ToString() + " years ago";
      } else {
      stringy = "1 year ago";
      }
      } else if (weeks >= 1) {
      if ((days - weeks * 7) > 0) {
      if ((days - weeks * 7) > 1) {
      stringy = ", " + (days - weeks * 7).ToString() + " days";
      } else {
      stringy = ", " + (days - weeks * 7).ToString() + " day";
      }
      }
      if (weeks >= 2) {
      stringy = weeks.ToString() + " weeks" + stringy + " ago";
      } else {
      stringy = "1 week" + stringy + " ago";
      }
      } else if (days >= 1) {
      if ((hours - days * 24) > 0) {
      if ((hours - days * 24) > 1) {
      stringy = ", " + (hours - days * 24).ToString() + " hours";
      } else {
      stringy = ", " + (hours - days * 24).ToString() + " hour";
      }
      }
      if (days >= 2) {
      stringy = days.ToString() + " days" + stringy + " ago";
      } else {
      stringy = "1 day" + stringy + " ago";
      }
      } else if (hours >= 1) {
      if ((minutes - hours * 60) > 0) {
      if ((minutes - hours * 60) > 1) {
      stringy = ", " + (minutes - hours * 60).ToString() + " minutes";
      } else {
      stringy = ", " + (minutes - hours * 60).ToString() + " minute";
      }
      }
      if (hours >= 2) {
      stringy = hours.ToString() + " hours" + stringy + " ago";
      } else {
      stringy = "1 hour" + stringy + " ago";
      }
      } else if (minutes > 1) {
      stringy = minutes.ToString() + " minutes ago";
      }
      return stringy;
      }









      share|improve this question















      I have this "pretty" date string generator in C# - pass it a date and it returns a string with "5 minutes ago" or "2 weeks, 3 days ago", etc.



      It's a little verbose and hogs 61 lines, and I'm wondering if I'm missing out on some nice C# features or something. What (if any) is the best way to clean up this code? Are there any cool c# features I can use here?



      public static string getTimeSpan(DateTime postDate)
      {
      string stringy = "";
      TimeSpan diff = DateTime.Now.Subtract(postDate);
      double years = Math.Floor(diff.TotalDays / 365);
      double weeks = Math.Floor(diff.TotalDays / 7);
      double days = diff.Days;
      double hours = diff.Hours + days * 24;
      double minutes = diff.Minutes + hours * 60;
      if (minutes <= 1) {
      stringy = "Just Now";
      } else if (years >= 1) {
      if (years >= 2) {
      stringy = years.ToString() + " years ago";
      } else {
      stringy = "1 year ago";
      }
      } else if (weeks >= 1) {
      if ((days - weeks * 7) > 0) {
      if ((days - weeks * 7) > 1) {
      stringy = ", " + (days - weeks * 7).ToString() + " days";
      } else {
      stringy = ", " + (days - weeks * 7).ToString() + " day";
      }
      }
      if (weeks >= 2) {
      stringy = weeks.ToString() + " weeks" + stringy + " ago";
      } else {
      stringy = "1 week" + stringy + " ago";
      }
      } else if (days >= 1) {
      if ((hours - days * 24) > 0) {
      if ((hours - days * 24) > 1) {
      stringy = ", " + (hours - days * 24).ToString() + " hours";
      } else {
      stringy = ", " + (hours - days * 24).ToString() + " hour";
      }
      }
      if (days >= 2) {
      stringy = days.ToString() + " days" + stringy + " ago";
      } else {
      stringy = "1 day" + stringy + " ago";
      }
      } else if (hours >= 1) {
      if ((minutes - hours * 60) > 0) {
      if ((minutes - hours * 60) > 1) {
      stringy = ", " + (minutes - hours * 60).ToString() + " minutes";
      } else {
      stringy = ", " + (minutes - hours * 60).ToString() + " minute";
      }
      }
      if (hours >= 2) {
      stringy = hours.ToString() + " hours" + stringy + " ago";
      } else {
      stringy = "1 hour" + stringy + " ago";
      }
      } else if (minutes > 1) {
      stringy = minutes.ToString() + " minutes ago";
      }
      return stringy;
      }






      c# datetime






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 6 '15 at 13:30









      Jamal

      30.2k11116226




      30.2k11116226










      asked May 31 '11 at 16:51









      Thomas Shields

      238313




      238313






















          4 Answers
          4






          active

          oldest

          votes


















          8















          1. Use PascalCase for the method name

          2. Move the calc for years and months lower to be minutely "more efficient"

          3. Use inline return to reduces nesting

          4. Use ternary operator (?:) for simple logic to reduce if/else clutter

          5. Use the format override of ToString(string format) to reduce string concats

          6. Use string.Format with a ternary to reduce duplication


          The shorter version I came up with is 40 lines, but you can judge if it readable enough.



              public static string GetTimeSpan(DateTime postDate) {
          string stringy = string.Empty;
          TimeSpan diff = DateTime.Now.Subtract(postDate);
          double days = diff.Days;
          double hours = diff.Hours + days*24;
          double minutes = diff.Minutes + hours*60;
          if (minutes <= 1) {
          return "Just Now";
          }
          double years = Math.Floor(diff.TotalDays/365);
          if (years >= 1) {
          return string.Format("{0} year{1} ago", years, years >= 2 ? "s" : null);
          }
          double weeks = Math.Floor(diff.TotalDays/7);
          if (weeks >= 1) {
          double partOfWeek = days - weeks*7;
          if (partOfWeek > 0) {
          stringy = string.Format(", {0} day{1}", partOfWeek, partOfWeek > 1 ? "s" : null);
          }
          return string.Format("{0} week{1}{2} ago", weeks, weeks >= 2 ? "s" : null, stringy);
          }
          if (days >= 1) {
          double partOfDay = hours - days*24;
          if (partOfDay > 0) {
          stringy = string.Format(", {0} hour{1}", partOfDay, partOfDay > 1 ? "s" : null);
          }
          return string.Format("{0} day{1}{2} ago", days, days >= 2 ? "s" : null, stringy);
          }
          if (hours >= 1) {
          double partOfHour = minutes - hours*60;
          if (partOfHour > 0) {
          stringy = string.Format(", {0} minute{1}", partOfHour, partOfHour > 1 ? "s" : null);
          }
          return string.Format("{0} hour{1}{2} ago", hours, hours >= 2 ? "s" : null, stringy);
          }

          // Only condition left is minutes > 1
          return minutes.ToString("{0} minutes ago");
          }





          share|improve this answer























          • wow thanks! I didn't even know about half these operators and methods and such!
            – Thomas Shields
            May 31 '11 at 20:46










          • It is important to remove last return in such cases so compiler will verify that all cases are checked and handled and there is no scenario when this method will return initial value which is string.Empty
            – Snowbear
            May 31 '11 at 22:05










          • Updated the last line to be more explicit with the final return.
            – Ed Chapel
            May 31 '11 at 22:30










          • How about future dates? :p
            – Chibueze Opata
            Sep 15 '15 at 19:03



















          4














          Some things are repeated:



          days - weeks * 7
          hours - days * 24
          minutes - hours * 60


          These can and should be made into their own variables - but what you are really after seems to be



          days % 7
          hours % 24
          minutes % 60


          You can replace:



          double hours = diff.Hours + days * 24;


          with



          double hours = diff.TotalHours;


          There is also a TotalMinutes. You can just use the Math.Floor() of these values to get an int.



          I see that you are going for a single exit point for this function, but I think that readability would be improved if you got some of the simpler paths shorter:



          if (minutes <= 1)         
          return "Just Now";

          if (years >= 1) {
          if (years >= 2) {
          return years.ToString() + " years ago";
          } else {
          return "1 year ago";
          }


          EDIT to add:



          There's a repeated block of code that could be refactored to its own function:



          if ((days - weeks * 7) > 0) {
          if ((days - weeks * 7) > 1) {
          stringy = ", " + (days - weeks * 7).ToString() + " days";
          } else {
          stringy = ", " + (days - weeks * 7).ToString() + " day";
          }
          }
          if (weeks >= 2) {
          stringy = weeks.ToString() + " weeks" + stringy + " ago";
          } else {
          stringy = "1 week" + stringy + " ago";
          }


          The body of the extracted function would look like:



          if (smallUnitCount > 0) {
          if (smallUnitCount > 1) {
          stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitPluralName);
          } else {
          stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitSingularName);
          }
          }
          if (largeUnitCount >= 2) {
          stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitPluralName, stringy);
          } else {
          stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitSingularName, stringy);
          }





          share|improve this answer































            3














            I would use casting double to int instead of Floor in your case. Firstly because I'm a little bit cautious about equality comparison of doubles in years >= 1. I would write it in this way:



            int years = (int)(diff.TotalDays/365);





            share|improve this answer





















            • would doing so accomplish the same as Floor? that is, would casting .8 to an int return 0? Because that's important (i don't want .8 to round to 1 and have the function say that it's been a year when it's only really been 80% of a year)
              – Thomas Shields
              May 31 '11 at 21:35






            • 1




              Yep, with positive doubles casting to int does Floor exactly. See Explicit conversion section here. It has exactly your sample.
              – Snowbear
              May 31 '11 at 21:48



















            0














            You can make it an extension, so you can do



            string result = DateTime.Now.GetTimeSpan();


            Here is how I did it a few time ago



              /// <summary>
            /// Provide extentions for the DateTime Object.
            /// </summary>
            public static class DateTimeExtensions
            {
            /// <summary>
            /// Gets the relative time for a datetime.
            /// </summary>
            /// <param name="dateTime">The datetime to get the relative time.</param>
            /// <returns>A relative time in english.</returns>
            public static string GetTimeSpan(this DateTime dateTime)
            {
            TimeSpan diff = DateTime.Now.Subtract(dateTime);

            if (diff.TotalMinutes < 1)
            {
            return string.Format("{0:D2} second{1} ago", diff.Seconds, PluralizeIfNeeded(diff.Seconds));
            }

            if (diff.TotalHours < 1)
            {
            return string.Format("{0:D2} minute{1} ago", diff.Minutes, PluralizeIfNeeded(diff.Minutes));
            }

            if (diff.TotalDays < 1)
            {
            return string.Format("{0:D2} hour{2} and {1:D2} minute{3} ago", diff.Hours, diff.Minutes, PluralizeIfNeeded(diff.Hours), PluralizeIfNeeded(diff.Minutes));
            }

            if (diff.TotalDays <= 2)
            {
            return string.Format(
            "{0:D2} day{3}, {1:D2} hour{4} and {2:D2} minute{5} ago",
            diff.Days,
            diff.Hours,
            diff.Minutes,
            PluralizeIfNeeded(diff.Days),
            PluralizeIfNeeded(diff.Hours),
            PluralizeIfNeeded(diff.Minutes));
            }

            if (diff.TotalDays <= 30)
            {
            return string.Format("{0:D2} days ago", diff.TotalDays);
            }

            return string.Format("{0:g}", dateTime);
            }

            /// <summary>
            /// Gets a 's' if value is > 1.
            /// </summary>
            /// <param name="testValue">The value to test.</param>
            /// <returns>An 's' if value is > 1, otherwise an empty string.</returns>
            private static string PluralizeIfNeeded(int testValue)
            {
            return testValue > 1 ? "s" : string.Empty;
            }
            }





            share|improve this answer





















              Your Answer





              StackExchange.ifUsing("editor", function () {
              return StackExchange.using("mathjaxEditing", function () {
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              });
              });
              }, "mathjax-editing");

              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "196"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f2738%2fpretty-date-generator%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              4 Answers
              4






              active

              oldest

              votes








              4 Answers
              4






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              8















              1. Use PascalCase for the method name

              2. Move the calc for years and months lower to be minutely "more efficient"

              3. Use inline return to reduces nesting

              4. Use ternary operator (?:) for simple logic to reduce if/else clutter

              5. Use the format override of ToString(string format) to reduce string concats

              6. Use string.Format with a ternary to reduce duplication


              The shorter version I came up with is 40 lines, but you can judge if it readable enough.



                  public static string GetTimeSpan(DateTime postDate) {
              string stringy = string.Empty;
              TimeSpan diff = DateTime.Now.Subtract(postDate);
              double days = diff.Days;
              double hours = diff.Hours + days*24;
              double minutes = diff.Minutes + hours*60;
              if (minutes <= 1) {
              return "Just Now";
              }
              double years = Math.Floor(diff.TotalDays/365);
              if (years >= 1) {
              return string.Format("{0} year{1} ago", years, years >= 2 ? "s" : null);
              }
              double weeks = Math.Floor(diff.TotalDays/7);
              if (weeks >= 1) {
              double partOfWeek = days - weeks*7;
              if (partOfWeek > 0) {
              stringy = string.Format(", {0} day{1}", partOfWeek, partOfWeek > 1 ? "s" : null);
              }
              return string.Format("{0} week{1}{2} ago", weeks, weeks >= 2 ? "s" : null, stringy);
              }
              if (days >= 1) {
              double partOfDay = hours - days*24;
              if (partOfDay > 0) {
              stringy = string.Format(", {0} hour{1}", partOfDay, partOfDay > 1 ? "s" : null);
              }
              return string.Format("{0} day{1}{2} ago", days, days >= 2 ? "s" : null, stringy);
              }
              if (hours >= 1) {
              double partOfHour = minutes - hours*60;
              if (partOfHour > 0) {
              stringy = string.Format(", {0} minute{1}", partOfHour, partOfHour > 1 ? "s" : null);
              }
              return string.Format("{0} hour{1}{2} ago", hours, hours >= 2 ? "s" : null, stringy);
              }

              // Only condition left is minutes > 1
              return minutes.ToString("{0} minutes ago");
              }





              share|improve this answer























              • wow thanks! I didn't even know about half these operators and methods and such!
                – Thomas Shields
                May 31 '11 at 20:46










              • It is important to remove last return in such cases so compiler will verify that all cases are checked and handled and there is no scenario when this method will return initial value which is string.Empty
                – Snowbear
                May 31 '11 at 22:05










              • Updated the last line to be more explicit with the final return.
                – Ed Chapel
                May 31 '11 at 22:30










              • How about future dates? :p
                – Chibueze Opata
                Sep 15 '15 at 19:03
















              8















              1. Use PascalCase for the method name

              2. Move the calc for years and months lower to be minutely "more efficient"

              3. Use inline return to reduces nesting

              4. Use ternary operator (?:) for simple logic to reduce if/else clutter

              5. Use the format override of ToString(string format) to reduce string concats

              6. Use string.Format with a ternary to reduce duplication


              The shorter version I came up with is 40 lines, but you can judge if it readable enough.



                  public static string GetTimeSpan(DateTime postDate) {
              string stringy = string.Empty;
              TimeSpan diff = DateTime.Now.Subtract(postDate);
              double days = diff.Days;
              double hours = diff.Hours + days*24;
              double minutes = diff.Minutes + hours*60;
              if (minutes <= 1) {
              return "Just Now";
              }
              double years = Math.Floor(diff.TotalDays/365);
              if (years >= 1) {
              return string.Format("{0} year{1} ago", years, years >= 2 ? "s" : null);
              }
              double weeks = Math.Floor(diff.TotalDays/7);
              if (weeks >= 1) {
              double partOfWeek = days - weeks*7;
              if (partOfWeek > 0) {
              stringy = string.Format(", {0} day{1}", partOfWeek, partOfWeek > 1 ? "s" : null);
              }
              return string.Format("{0} week{1}{2} ago", weeks, weeks >= 2 ? "s" : null, stringy);
              }
              if (days >= 1) {
              double partOfDay = hours - days*24;
              if (partOfDay > 0) {
              stringy = string.Format(", {0} hour{1}", partOfDay, partOfDay > 1 ? "s" : null);
              }
              return string.Format("{0} day{1}{2} ago", days, days >= 2 ? "s" : null, stringy);
              }
              if (hours >= 1) {
              double partOfHour = minutes - hours*60;
              if (partOfHour > 0) {
              stringy = string.Format(", {0} minute{1}", partOfHour, partOfHour > 1 ? "s" : null);
              }
              return string.Format("{0} hour{1}{2} ago", hours, hours >= 2 ? "s" : null, stringy);
              }

              // Only condition left is minutes > 1
              return minutes.ToString("{0} minutes ago");
              }





              share|improve this answer























              • wow thanks! I didn't even know about half these operators and methods and such!
                – Thomas Shields
                May 31 '11 at 20:46










              • It is important to remove last return in such cases so compiler will verify that all cases are checked and handled and there is no scenario when this method will return initial value which is string.Empty
                – Snowbear
                May 31 '11 at 22:05










              • Updated the last line to be more explicit with the final return.
                – Ed Chapel
                May 31 '11 at 22:30










              • How about future dates? :p
                – Chibueze Opata
                Sep 15 '15 at 19:03














              8












              8








              8







              1. Use PascalCase for the method name

              2. Move the calc for years and months lower to be minutely "more efficient"

              3. Use inline return to reduces nesting

              4. Use ternary operator (?:) for simple logic to reduce if/else clutter

              5. Use the format override of ToString(string format) to reduce string concats

              6. Use string.Format with a ternary to reduce duplication


              The shorter version I came up with is 40 lines, but you can judge if it readable enough.



                  public static string GetTimeSpan(DateTime postDate) {
              string stringy = string.Empty;
              TimeSpan diff = DateTime.Now.Subtract(postDate);
              double days = diff.Days;
              double hours = diff.Hours + days*24;
              double minutes = diff.Minutes + hours*60;
              if (minutes <= 1) {
              return "Just Now";
              }
              double years = Math.Floor(diff.TotalDays/365);
              if (years >= 1) {
              return string.Format("{0} year{1} ago", years, years >= 2 ? "s" : null);
              }
              double weeks = Math.Floor(diff.TotalDays/7);
              if (weeks >= 1) {
              double partOfWeek = days - weeks*7;
              if (partOfWeek > 0) {
              stringy = string.Format(", {0} day{1}", partOfWeek, partOfWeek > 1 ? "s" : null);
              }
              return string.Format("{0} week{1}{2} ago", weeks, weeks >= 2 ? "s" : null, stringy);
              }
              if (days >= 1) {
              double partOfDay = hours - days*24;
              if (partOfDay > 0) {
              stringy = string.Format(", {0} hour{1}", partOfDay, partOfDay > 1 ? "s" : null);
              }
              return string.Format("{0} day{1}{2} ago", days, days >= 2 ? "s" : null, stringy);
              }
              if (hours >= 1) {
              double partOfHour = minutes - hours*60;
              if (partOfHour > 0) {
              stringy = string.Format(", {0} minute{1}", partOfHour, partOfHour > 1 ? "s" : null);
              }
              return string.Format("{0} hour{1}{2} ago", hours, hours >= 2 ? "s" : null, stringy);
              }

              // Only condition left is minutes > 1
              return minutes.ToString("{0} minutes ago");
              }





              share|improve this answer















              1. Use PascalCase for the method name

              2. Move the calc for years and months lower to be minutely "more efficient"

              3. Use inline return to reduces nesting

              4. Use ternary operator (?:) for simple logic to reduce if/else clutter

              5. Use the format override of ToString(string format) to reduce string concats

              6. Use string.Format with a ternary to reduce duplication


              The shorter version I came up with is 40 lines, but you can judge if it readable enough.



                  public static string GetTimeSpan(DateTime postDate) {
              string stringy = string.Empty;
              TimeSpan diff = DateTime.Now.Subtract(postDate);
              double days = diff.Days;
              double hours = diff.Hours + days*24;
              double minutes = diff.Minutes + hours*60;
              if (minutes <= 1) {
              return "Just Now";
              }
              double years = Math.Floor(diff.TotalDays/365);
              if (years >= 1) {
              return string.Format("{0} year{1} ago", years, years >= 2 ? "s" : null);
              }
              double weeks = Math.Floor(diff.TotalDays/7);
              if (weeks >= 1) {
              double partOfWeek = days - weeks*7;
              if (partOfWeek > 0) {
              stringy = string.Format(", {0} day{1}", partOfWeek, partOfWeek > 1 ? "s" : null);
              }
              return string.Format("{0} week{1}{2} ago", weeks, weeks >= 2 ? "s" : null, stringy);
              }
              if (days >= 1) {
              double partOfDay = hours - days*24;
              if (partOfDay > 0) {
              stringy = string.Format(", {0} hour{1}", partOfDay, partOfDay > 1 ? "s" : null);
              }
              return string.Format("{0} day{1}{2} ago", days, days >= 2 ? "s" : null, stringy);
              }
              if (hours >= 1) {
              double partOfHour = minutes - hours*60;
              if (partOfHour > 0) {
              stringy = string.Format(", {0} minute{1}", partOfHour, partOfHour > 1 ? "s" : null);
              }
              return string.Format("{0} hour{1}{2} ago", hours, hours >= 2 ? "s" : null, stringy);
              }

              // Only condition left is minutes > 1
              return minutes.ToString("{0} minutes ago");
              }






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Mar 6 '15 at 13:25









              Heslacher

              44.8k460155




              44.8k460155










              answered May 31 '11 at 20:37









              Ed Chapel

              29615




              29615












              • wow thanks! I didn't even know about half these operators and methods and such!
                – Thomas Shields
                May 31 '11 at 20:46










              • It is important to remove last return in such cases so compiler will verify that all cases are checked and handled and there is no scenario when this method will return initial value which is string.Empty
                – Snowbear
                May 31 '11 at 22:05










              • Updated the last line to be more explicit with the final return.
                – Ed Chapel
                May 31 '11 at 22:30










              • How about future dates? :p
                – Chibueze Opata
                Sep 15 '15 at 19:03


















              • wow thanks! I didn't even know about half these operators and methods and such!
                – Thomas Shields
                May 31 '11 at 20:46










              • It is important to remove last return in such cases so compiler will verify that all cases are checked and handled and there is no scenario when this method will return initial value which is string.Empty
                – Snowbear
                May 31 '11 at 22:05










              • Updated the last line to be more explicit with the final return.
                – Ed Chapel
                May 31 '11 at 22:30










              • How about future dates? :p
                – Chibueze Opata
                Sep 15 '15 at 19:03
















              wow thanks! I didn't even know about half these operators and methods and such!
              – Thomas Shields
              May 31 '11 at 20:46




              wow thanks! I didn't even know about half these operators and methods and such!
              – Thomas Shields
              May 31 '11 at 20:46












              It is important to remove last return in such cases so compiler will verify that all cases are checked and handled and there is no scenario when this method will return initial value which is string.Empty
              – Snowbear
              May 31 '11 at 22:05




              It is important to remove last return in such cases so compiler will verify that all cases are checked and handled and there is no scenario when this method will return initial value which is string.Empty
              – Snowbear
              May 31 '11 at 22:05












              Updated the last line to be more explicit with the final return.
              – Ed Chapel
              May 31 '11 at 22:30




              Updated the last line to be more explicit with the final return.
              – Ed Chapel
              May 31 '11 at 22:30












              How about future dates? :p
              – Chibueze Opata
              Sep 15 '15 at 19:03




              How about future dates? :p
              – Chibueze Opata
              Sep 15 '15 at 19:03













              4














              Some things are repeated:



              days - weeks * 7
              hours - days * 24
              minutes - hours * 60


              These can and should be made into their own variables - but what you are really after seems to be



              days % 7
              hours % 24
              minutes % 60


              You can replace:



              double hours = diff.Hours + days * 24;


              with



              double hours = diff.TotalHours;


              There is also a TotalMinutes. You can just use the Math.Floor() of these values to get an int.



              I see that you are going for a single exit point for this function, but I think that readability would be improved if you got some of the simpler paths shorter:



              if (minutes <= 1)         
              return "Just Now";

              if (years >= 1) {
              if (years >= 2) {
              return years.ToString() + " years ago";
              } else {
              return "1 year ago";
              }


              EDIT to add:



              There's a repeated block of code that could be refactored to its own function:



              if ((days - weeks * 7) > 0) {
              if ((days - weeks * 7) > 1) {
              stringy = ", " + (days - weeks * 7).ToString() + " days";
              } else {
              stringy = ", " + (days - weeks * 7).ToString() + " day";
              }
              }
              if (weeks >= 2) {
              stringy = weeks.ToString() + " weeks" + stringy + " ago";
              } else {
              stringy = "1 week" + stringy + " ago";
              }


              The body of the extracted function would look like:



              if (smallUnitCount > 0) {
              if (smallUnitCount > 1) {
              stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitPluralName);
              } else {
              stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitSingularName);
              }
              }
              if (largeUnitCount >= 2) {
              stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitPluralName, stringy);
              } else {
              stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitSingularName, stringy);
              }





              share|improve this answer




























                4














                Some things are repeated:



                days - weeks * 7
                hours - days * 24
                minutes - hours * 60


                These can and should be made into their own variables - but what you are really after seems to be



                days % 7
                hours % 24
                minutes % 60


                You can replace:



                double hours = diff.Hours + days * 24;


                with



                double hours = diff.TotalHours;


                There is also a TotalMinutes. You can just use the Math.Floor() of these values to get an int.



                I see that you are going for a single exit point for this function, but I think that readability would be improved if you got some of the simpler paths shorter:



                if (minutes <= 1)         
                return "Just Now";

                if (years >= 1) {
                if (years >= 2) {
                return years.ToString() + " years ago";
                } else {
                return "1 year ago";
                }


                EDIT to add:



                There's a repeated block of code that could be refactored to its own function:



                if ((days - weeks * 7) > 0) {
                if ((days - weeks * 7) > 1) {
                stringy = ", " + (days - weeks * 7).ToString() + " days";
                } else {
                stringy = ", " + (days - weeks * 7).ToString() + " day";
                }
                }
                if (weeks >= 2) {
                stringy = weeks.ToString() + " weeks" + stringy + " ago";
                } else {
                stringy = "1 week" + stringy + " ago";
                }


                The body of the extracted function would look like:



                if (smallUnitCount > 0) {
                if (smallUnitCount > 1) {
                stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitPluralName);
                } else {
                stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitSingularName);
                }
                }
                if (largeUnitCount >= 2) {
                stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitPluralName, stringy);
                } else {
                stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitSingularName, stringy);
                }





                share|improve this answer


























                  4












                  4








                  4






                  Some things are repeated:



                  days - weeks * 7
                  hours - days * 24
                  minutes - hours * 60


                  These can and should be made into their own variables - but what you are really after seems to be



                  days % 7
                  hours % 24
                  minutes % 60


                  You can replace:



                  double hours = diff.Hours + days * 24;


                  with



                  double hours = diff.TotalHours;


                  There is also a TotalMinutes. You can just use the Math.Floor() of these values to get an int.



                  I see that you are going for a single exit point for this function, but I think that readability would be improved if you got some of the simpler paths shorter:



                  if (minutes <= 1)         
                  return "Just Now";

                  if (years >= 1) {
                  if (years >= 2) {
                  return years.ToString() + " years ago";
                  } else {
                  return "1 year ago";
                  }


                  EDIT to add:



                  There's a repeated block of code that could be refactored to its own function:



                  if ((days - weeks * 7) > 0) {
                  if ((days - weeks * 7) > 1) {
                  stringy = ", " + (days - weeks * 7).ToString() + " days";
                  } else {
                  stringy = ", " + (days - weeks * 7).ToString() + " day";
                  }
                  }
                  if (weeks >= 2) {
                  stringy = weeks.ToString() + " weeks" + stringy + " ago";
                  } else {
                  stringy = "1 week" + stringy + " ago";
                  }


                  The body of the extracted function would look like:



                  if (smallUnitCount > 0) {
                  if (smallUnitCount > 1) {
                  stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitPluralName);
                  } else {
                  stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitSingularName);
                  }
                  }
                  if (largeUnitCount >= 2) {
                  stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitPluralName, stringy);
                  } else {
                  stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitSingularName, stringy);
                  }





                  share|improve this answer














                  Some things are repeated:



                  days - weeks * 7
                  hours - days * 24
                  minutes - hours * 60


                  These can and should be made into their own variables - but what you are really after seems to be



                  days % 7
                  hours % 24
                  minutes % 60


                  You can replace:



                  double hours = diff.Hours + days * 24;


                  with



                  double hours = diff.TotalHours;


                  There is also a TotalMinutes. You can just use the Math.Floor() of these values to get an int.



                  I see that you are going for a single exit point for this function, but I think that readability would be improved if you got some of the simpler paths shorter:



                  if (minutes <= 1)         
                  return "Just Now";

                  if (years >= 1) {
                  if (years >= 2) {
                  return years.ToString() + " years ago";
                  } else {
                  return "1 year ago";
                  }


                  EDIT to add:



                  There's a repeated block of code that could be refactored to its own function:



                  if ((days - weeks * 7) > 0) {
                  if ((days - weeks * 7) > 1) {
                  stringy = ", " + (days - weeks * 7).ToString() + " days";
                  } else {
                  stringy = ", " + (days - weeks * 7).ToString() + " day";
                  }
                  }
                  if (weeks >= 2) {
                  stringy = weeks.ToString() + " weeks" + stringy + " ago";
                  } else {
                  stringy = "1 week" + stringy + " ago";
                  }


                  The body of the extracted function would look like:



                  if (smallUnitCount > 0) {
                  if (smallUnitCount > 1) {
                  stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitPluralName);
                  } else {
                  stringy = String.Format(", {0} {1}", smallUnitCount.ToString() , smallUnitSingularName);
                  }
                  }
                  if (largeUnitCount >= 2) {
                  stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitPluralName, stringy);
                  } else {
                  stringy = String.Format("{0} {1}{2} ago", largeUnitCount.ToString, largeUnitSingularName, stringy);
                  }






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited May 31 '11 at 20:36

























                  answered May 31 '11 at 19:49









                  Jeff Paulsen

                  31114




                  31114























                      3














                      I would use casting double to int instead of Floor in your case. Firstly because I'm a little bit cautious about equality comparison of doubles in years >= 1. I would write it in this way:



                      int years = (int)(diff.TotalDays/365);





                      share|improve this answer





















                      • would doing so accomplish the same as Floor? that is, would casting .8 to an int return 0? Because that's important (i don't want .8 to round to 1 and have the function say that it's been a year when it's only really been 80% of a year)
                        – Thomas Shields
                        May 31 '11 at 21:35






                      • 1




                        Yep, with positive doubles casting to int does Floor exactly. See Explicit conversion section here. It has exactly your sample.
                        – Snowbear
                        May 31 '11 at 21:48
















                      3














                      I would use casting double to int instead of Floor in your case. Firstly because I'm a little bit cautious about equality comparison of doubles in years >= 1. I would write it in this way:



                      int years = (int)(diff.TotalDays/365);





                      share|improve this answer





















                      • would doing so accomplish the same as Floor? that is, would casting .8 to an int return 0? Because that's important (i don't want .8 to round to 1 and have the function say that it's been a year when it's only really been 80% of a year)
                        – Thomas Shields
                        May 31 '11 at 21:35






                      • 1




                        Yep, with positive doubles casting to int does Floor exactly. See Explicit conversion section here. It has exactly your sample.
                        – Snowbear
                        May 31 '11 at 21:48














                      3












                      3








                      3






                      I would use casting double to int instead of Floor in your case. Firstly because I'm a little bit cautious about equality comparison of doubles in years >= 1. I would write it in this way:



                      int years = (int)(diff.TotalDays/365);





                      share|improve this answer












                      I would use casting double to int instead of Floor in your case. Firstly because I'm a little bit cautious about equality comparison of doubles in years >= 1. I would write it in this way:



                      int years = (int)(diff.TotalDays/365);






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered May 31 '11 at 21:30









                      Snowbear

                      3,50311323




                      3,50311323












                      • would doing so accomplish the same as Floor? that is, would casting .8 to an int return 0? Because that's important (i don't want .8 to round to 1 and have the function say that it's been a year when it's only really been 80% of a year)
                        – Thomas Shields
                        May 31 '11 at 21:35






                      • 1




                        Yep, with positive doubles casting to int does Floor exactly. See Explicit conversion section here. It has exactly your sample.
                        – Snowbear
                        May 31 '11 at 21:48


















                      • would doing so accomplish the same as Floor? that is, would casting .8 to an int return 0? Because that's important (i don't want .8 to round to 1 and have the function say that it's been a year when it's only really been 80% of a year)
                        – Thomas Shields
                        May 31 '11 at 21:35






                      • 1




                        Yep, with positive doubles casting to int does Floor exactly. See Explicit conversion section here. It has exactly your sample.
                        – Snowbear
                        May 31 '11 at 21:48
















                      would doing so accomplish the same as Floor? that is, would casting .8 to an int return 0? Because that's important (i don't want .8 to round to 1 and have the function say that it's been a year when it's only really been 80% of a year)
                      – Thomas Shields
                      May 31 '11 at 21:35




                      would doing so accomplish the same as Floor? that is, would casting .8 to an int return 0? Because that's important (i don't want .8 to round to 1 and have the function say that it's been a year when it's only really been 80% of a year)
                      – Thomas Shields
                      May 31 '11 at 21:35




                      1




                      1




                      Yep, with positive doubles casting to int does Floor exactly. See Explicit conversion section here. It has exactly your sample.
                      – Snowbear
                      May 31 '11 at 21:48




                      Yep, with positive doubles casting to int does Floor exactly. See Explicit conversion section here. It has exactly your sample.
                      – Snowbear
                      May 31 '11 at 21:48











                      0














                      You can make it an extension, so you can do



                      string result = DateTime.Now.GetTimeSpan();


                      Here is how I did it a few time ago



                        /// <summary>
                      /// Provide extentions for the DateTime Object.
                      /// </summary>
                      public static class DateTimeExtensions
                      {
                      /// <summary>
                      /// Gets the relative time for a datetime.
                      /// </summary>
                      /// <param name="dateTime">The datetime to get the relative time.</param>
                      /// <returns>A relative time in english.</returns>
                      public static string GetTimeSpan(this DateTime dateTime)
                      {
                      TimeSpan diff = DateTime.Now.Subtract(dateTime);

                      if (diff.TotalMinutes < 1)
                      {
                      return string.Format("{0:D2} second{1} ago", diff.Seconds, PluralizeIfNeeded(diff.Seconds));
                      }

                      if (diff.TotalHours < 1)
                      {
                      return string.Format("{0:D2} minute{1} ago", diff.Minutes, PluralizeIfNeeded(diff.Minutes));
                      }

                      if (diff.TotalDays < 1)
                      {
                      return string.Format("{0:D2} hour{2} and {1:D2} minute{3} ago", diff.Hours, diff.Minutes, PluralizeIfNeeded(diff.Hours), PluralizeIfNeeded(diff.Minutes));
                      }

                      if (diff.TotalDays <= 2)
                      {
                      return string.Format(
                      "{0:D2} day{3}, {1:D2} hour{4} and {2:D2} minute{5} ago",
                      diff.Days,
                      diff.Hours,
                      diff.Minutes,
                      PluralizeIfNeeded(diff.Days),
                      PluralizeIfNeeded(diff.Hours),
                      PluralizeIfNeeded(diff.Minutes));
                      }

                      if (diff.TotalDays <= 30)
                      {
                      return string.Format("{0:D2} days ago", diff.TotalDays);
                      }

                      return string.Format("{0:g}", dateTime);
                      }

                      /// <summary>
                      /// Gets a 's' if value is > 1.
                      /// </summary>
                      /// <param name="testValue">The value to test.</param>
                      /// <returns>An 's' if value is > 1, otherwise an empty string.</returns>
                      private static string PluralizeIfNeeded(int testValue)
                      {
                      return testValue > 1 ? "s" : string.Empty;
                      }
                      }





                      share|improve this answer


























                        0














                        You can make it an extension, so you can do



                        string result = DateTime.Now.GetTimeSpan();


                        Here is how I did it a few time ago



                          /// <summary>
                        /// Provide extentions for the DateTime Object.
                        /// </summary>
                        public static class DateTimeExtensions
                        {
                        /// <summary>
                        /// Gets the relative time for a datetime.
                        /// </summary>
                        /// <param name="dateTime">The datetime to get the relative time.</param>
                        /// <returns>A relative time in english.</returns>
                        public static string GetTimeSpan(this DateTime dateTime)
                        {
                        TimeSpan diff = DateTime.Now.Subtract(dateTime);

                        if (diff.TotalMinutes < 1)
                        {
                        return string.Format("{0:D2} second{1} ago", diff.Seconds, PluralizeIfNeeded(diff.Seconds));
                        }

                        if (diff.TotalHours < 1)
                        {
                        return string.Format("{0:D2} minute{1} ago", diff.Minutes, PluralizeIfNeeded(diff.Minutes));
                        }

                        if (diff.TotalDays < 1)
                        {
                        return string.Format("{0:D2} hour{2} and {1:D2} minute{3} ago", diff.Hours, diff.Minutes, PluralizeIfNeeded(diff.Hours), PluralizeIfNeeded(diff.Minutes));
                        }

                        if (diff.TotalDays <= 2)
                        {
                        return string.Format(
                        "{0:D2} day{3}, {1:D2} hour{4} and {2:D2} minute{5} ago",
                        diff.Days,
                        diff.Hours,
                        diff.Minutes,
                        PluralizeIfNeeded(diff.Days),
                        PluralizeIfNeeded(diff.Hours),
                        PluralizeIfNeeded(diff.Minutes));
                        }

                        if (diff.TotalDays <= 30)
                        {
                        return string.Format("{0:D2} days ago", diff.TotalDays);
                        }

                        return string.Format("{0:g}", dateTime);
                        }

                        /// <summary>
                        /// Gets a 's' if value is > 1.
                        /// </summary>
                        /// <param name="testValue">The value to test.</param>
                        /// <returns>An 's' if value is > 1, otherwise an empty string.</returns>
                        private static string PluralizeIfNeeded(int testValue)
                        {
                        return testValue > 1 ? "s" : string.Empty;
                        }
                        }





                        share|improve this answer
























                          0












                          0








                          0






                          You can make it an extension, so you can do



                          string result = DateTime.Now.GetTimeSpan();


                          Here is how I did it a few time ago



                            /// <summary>
                          /// Provide extentions for the DateTime Object.
                          /// </summary>
                          public static class DateTimeExtensions
                          {
                          /// <summary>
                          /// Gets the relative time for a datetime.
                          /// </summary>
                          /// <param name="dateTime">The datetime to get the relative time.</param>
                          /// <returns>A relative time in english.</returns>
                          public static string GetTimeSpan(this DateTime dateTime)
                          {
                          TimeSpan diff = DateTime.Now.Subtract(dateTime);

                          if (diff.TotalMinutes < 1)
                          {
                          return string.Format("{0:D2} second{1} ago", diff.Seconds, PluralizeIfNeeded(diff.Seconds));
                          }

                          if (diff.TotalHours < 1)
                          {
                          return string.Format("{0:D2} minute{1} ago", diff.Minutes, PluralizeIfNeeded(diff.Minutes));
                          }

                          if (diff.TotalDays < 1)
                          {
                          return string.Format("{0:D2} hour{2} and {1:D2} minute{3} ago", diff.Hours, diff.Minutes, PluralizeIfNeeded(diff.Hours), PluralizeIfNeeded(diff.Minutes));
                          }

                          if (diff.TotalDays <= 2)
                          {
                          return string.Format(
                          "{0:D2} day{3}, {1:D2} hour{4} and {2:D2} minute{5} ago",
                          diff.Days,
                          diff.Hours,
                          diff.Minutes,
                          PluralizeIfNeeded(diff.Days),
                          PluralizeIfNeeded(diff.Hours),
                          PluralizeIfNeeded(diff.Minutes));
                          }

                          if (diff.TotalDays <= 30)
                          {
                          return string.Format("{0:D2} days ago", diff.TotalDays);
                          }

                          return string.Format("{0:g}", dateTime);
                          }

                          /// <summary>
                          /// Gets a 's' if value is > 1.
                          /// </summary>
                          /// <param name="testValue">The value to test.</param>
                          /// <returns>An 's' if value is > 1, otherwise an empty string.</returns>
                          private static string PluralizeIfNeeded(int testValue)
                          {
                          return testValue > 1 ? "s" : string.Empty;
                          }
                          }





                          share|improve this answer












                          You can make it an extension, so you can do



                          string result = DateTime.Now.GetTimeSpan();


                          Here is how I did it a few time ago



                            /// <summary>
                          /// Provide extentions for the DateTime Object.
                          /// </summary>
                          public static class DateTimeExtensions
                          {
                          /// <summary>
                          /// Gets the relative time for a datetime.
                          /// </summary>
                          /// <param name="dateTime">The datetime to get the relative time.</param>
                          /// <returns>A relative time in english.</returns>
                          public static string GetTimeSpan(this DateTime dateTime)
                          {
                          TimeSpan diff = DateTime.Now.Subtract(dateTime);

                          if (diff.TotalMinutes < 1)
                          {
                          return string.Format("{0:D2} second{1} ago", diff.Seconds, PluralizeIfNeeded(diff.Seconds));
                          }

                          if (diff.TotalHours < 1)
                          {
                          return string.Format("{0:D2} minute{1} ago", diff.Minutes, PluralizeIfNeeded(diff.Minutes));
                          }

                          if (diff.TotalDays < 1)
                          {
                          return string.Format("{0:D2} hour{2} and {1:D2} minute{3} ago", diff.Hours, diff.Minutes, PluralizeIfNeeded(diff.Hours), PluralizeIfNeeded(diff.Minutes));
                          }

                          if (diff.TotalDays <= 2)
                          {
                          return string.Format(
                          "{0:D2} day{3}, {1:D2} hour{4} and {2:D2} minute{5} ago",
                          diff.Days,
                          diff.Hours,
                          diff.Minutes,
                          PluralizeIfNeeded(diff.Days),
                          PluralizeIfNeeded(diff.Hours),
                          PluralizeIfNeeded(diff.Minutes));
                          }

                          if (diff.TotalDays <= 30)
                          {
                          return string.Format("{0:D2} days ago", diff.TotalDays);
                          }

                          return string.Format("{0:g}", dateTime);
                          }

                          /// <summary>
                          /// Gets a 's' if value is > 1.
                          /// </summary>
                          /// <param name="testValue">The value to test.</param>
                          /// <returns>An 's' if value is > 1, otherwise an empty string.</returns>
                          private static string PluralizeIfNeeded(int testValue)
                          {
                          return testValue > 1 ? "s" : string.Empty;
                          }
                          }






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Jun 1 '11 at 9:48









                          Sam

                          11




                          11






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Code Review Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              Use MathJax to format equations. MathJax reference.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f2738%2fpretty-date-generator%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Сан-Квентин

                              Алькесар

                              Josef Freinademetz