How do I automatically the Display TimeSpan Date without indicating day or time

Donald Symmons 2,856 Reputation points
2023-10-19T07:43:24.62+00:00

How can I display date TimeSpan of a post ?

For example, If I posted something on August 17, 2021 06:30AM, in the label it will display "Posted 2 years ago".

Or it will display like "2 years, 3 days ago". Or maybe add the time as well like "2 years, 3 days 1 hour 23 minutes 3 seconds ago".

I tried this but it displayed 87 days ago (and this depends on the Date of the post).

Because I have these timelbl.Text = $"Posted {(int)diff.TotalDays} days ago "; That is why I am having 87 days ago. I tried this too timelbl.Text = $"Posted {(int)diff.TotalHours} hours ago "; And it gave me this: 2106 hours ago

My question is, what if the Date and Time exceeds 1 year, or 4 years, can't it automatically adjust the display according to the Date and Time Span difference, depeneding on the PostedDate?

And display as "1 year, 23 days ago" or "4 years, 18 days ago", "2 years ago" or maybe "8 years ago" depending on the date?

 private void PopulatePost()
        {
            try
            {
                 string PostId = this.Page.RouteData.Values["Id"].ToString();
                 if (Id != null)
                 {
                    string query = "SELECT [Title], [Body], [DatePosted] FROM [Posts] WHERE [Id] = @Id";
                    string connectionString = ConfigurationManager.ConnectionStrings["ConString"].ConnectionString;
                    using (SqlConnection con = new SqlConnection(connectionString))
                    {
                        using (SqlCommand cmd = new SqlCommand(query))
                        {
                            using (SqlDataAdapter sda = new SqlDataAdapter())
                            {
                                cmd.Parameters.AddWithValue("@Id", PostId);
                                cmd.Connection = con;
                                sda.SelectCommand = cmd;
                                using (DataTable dt = new DataTable())
                                {
                                    sda.Fill(dt);
                                    lblBody.Text = dt.Rows[0]["Body"].ToString();
                                    TitleLabel.Text = dt.Rows[0]["Title"].ToString();

                                    DateTime PostedDateTime = Convert.ToDateTime(dt.Rows[0]["DatePosted"]);
                                    Thread.Sleep(3 * 1000);
                                    DateTime CurrentTime = DateTime.Now;

                                    TimeSpan diff = CurrentTime - PostedDateTime;
                                    timelbl.Text = $"Posted {(int)diff.TotalDays} days ago ";
                                 }
                            }
                        }
                    }
                 }
            }
            catch (SqlException ex)
            {
                string msg = "Error:";
                msg += ex.Message;
                throw new Exception(msg);
            }
        }
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,459 questions
ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,313 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,383 questions
{count} votes

Accepted answer
  1. Lan Huang-MSFT 26,516 Reputation points Microsoft Vendor
    2023-10-19T09:37:09.45+00:00

    Hi @Donald Symmons ,

    You just need to write an extension method and call it in the PopulatePost method.

      DateTime PostedDateTime = Convert.ToDateTime(dt.Rows[0]["DatePosted"]);
    
      string diff = getRelativeDateTime(PostedDateTime);
    
      timelbl.Text = $"Posted {diff} ";
    
     public string getRelativeDateTime(DateTime date)
     {
         var ts = new TimeSpan(DateTime.UtcNow.Ticks - date.Ticks);
         double delta = Math.Abs(ts.TotalSeconds);
    
         if (delta < 60)
         {
             return ts.Seconds == 1 ? "one second ago" : ts.Seconds + " seconds ago";
         }
         if (delta < 60 * 2)
         {
             return "a minute ago";
         }
         if (delta < 45 * 60)
         {
             return ts.Minutes + " minutes ago";
         }
         if (delta < 90 * 60)
         {
             return "an hour ago";
         }
         if (delta < 24 * 60 * 60)
         {
             return ts.Hours + " hours ago";
         }
         if (delta < 48 * 60 * 60)
         {
             return "yesterday";
         }
         if (delta < 30 * 24 * 60 * 60)
         {
             return ts.Days + " days ago";
         }
         if (delta < 12 * 30 * 24 * 60 * 60)
         {
             int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
             return months <= 1 ? "one month ago" : months + " months ago";
         }
         int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
         return years <= 1 ? "one year ago" : years + " years ago";
     }
    

    Best regards,
    Lan Huang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Karen Payne MVP 35,201 Reputation points
    2023-10-19T09:18:21.7166667+00:00

    What you have seems on the right track, perhaps the following might be of use, something I put together maybe ten years ago and added, today the code for displaying date information.

    By no means perfect in regards to logic for displaying but the underlying logic is sound.

    Usage

    var from = new DateTime(2023, 10, 19);
    Age result = from.Age(DateTime.Now);
    var posted = $"Posted {result.Posted()}";
    

    In the following model, Full, Posted and ToString where just added. Posted method is what I call dirty and cheap.

    public class Age
    {
        public int Years { get; set; }
        public int Months { get; set; }
        public int Days { get; set; }
        public int Hours { get; set; }
        public int Minutes { get; set; }
        public int Seconds { get; set; }
        public int Milliseconds { get; set; }
        /// <summary>
        /// Date to calculate off of a later date
        /// </summary>
        public DateTime From { get; set; }
        /// <summary>
        /// Date to calculate off a earlier date
        /// </summary>
        public DateTime To { get; set; }
    
        /// <summary>
        /// No logic if any member is 0
        /// </summary>
        public string Full(string text = "Posted ")
            => $"{text}" +
               $"{Years} years " +
               $"{Months} months " +
               $"{Days} days " +
               $"{Hours} hours " +
               $"{Minutes} minutes " +
               $"{Seconds} ago";
    
        public string Posted()
        {
            var data = 
                $"{Years} years " + 
                $"{Months} months " + 
                $"{Days} days " + 
                $"{Hours} hours " + 
                $"{Minutes} minutes " + 
                $"{Seconds} seconds ago";
    
            return data
                .Replace("0 years", "")
                .Replace("0 months", "")
                .Replace("0 days", "")
                .Replace("0 hours", "")
                .Replace("0 minutes", "")
                .TrimStart();
        }
    
    
        /// <summary>
        /// No logic for 0 on time portions
        /// </summary>
        public override string ToString()
        {
            if (Years > 0 && Months > 0 && Days > 0)
            {
                return $"{Years} years {Months} months {Days} days ago";
            }
            else if (Months > 0 && Days > 0)
            {
                return $"{Months} months {Days} days ago";
            }
            else if (Days > 0)
            {
                return $"{Days} days ago";
            }
            else
            {
                return "";
            }
        }
    }
    

    Then we have a language extension to keep client code clean.

    public static class DateTimeExtensions
    {
        /// <summary>
        /// Provides a wrapper for <see cref="GetElapsedTime"/> to keep client code clean
        /// </summary>
        /// <param name="fromDateTime">Pass date</param>
        /// <param name="toDate">Typically DateTime.Now</param>
        /// <returns><see cref="Age"/> instance</returns>
        /// <remarks>
        /// * Minimal assertion is done
        /// * milliseconds are provides but not much use
        /// </remarks>
        public static Age Age(this DateTime fromDateTime, DateTime toDate)
        {
    
            fromDateTime.GetElapsedTime(toDate,
                out var years, out var months, out var days,
                out var hours, out var minutes, out var seconds,
                out _);
    
            return new Age()
            {
                Years = years,
                Months = months,
                Days = days,
                Hours = hours,
                Minutes = minutes,
                Seconds = seconds,
                From = fromDateTime,
                To = toDate
            };
    
        }
        /// <summary>
        /// Get elapsed time in years, months, days, hours, seconds
        /// </summary>
        /// <param name="fromDate">Date in past</param>
        /// <param name="toDate">Date pass fromDate</param>
        /// <param name="years"></param>
        /// <param name="months"></param>
        /// <param name="days"></param>
        /// <param name="hours"></param>
        /// <param name="minutes"></param>
        /// <param name="seconds"></param>
        /// <param name="milliseconds"></param>
        public static void GetElapsedTime(this DateTime fromDate, DateTime toDate, out int years, out int months, out int days, out int hours, out int minutes, out int seconds, out int milliseconds)
        {
            // If from_date > to_date, switch them around.
            if (fromDate > toDate)
            {
                GetElapsedTime(
                    toDate,
                    fromDate,
                    out years,
                    out months,
                    out days,
                    out hours,
                    out minutes,
                    out seconds,
                    out milliseconds);
    
                years = -years;
                months = -months;
                days = -days;
                hours = -hours;
                minutes = -minutes;
                seconds = -seconds;
                milliseconds = -milliseconds;
            }
            else
            {
                // Handle the years.
                years = toDate.Year - fromDate.Year;
    
                // See if we went too far.
                DateTime testDate = fromDate.AddMonths(12 * years);
    
                if (testDate > toDate)
                {
                    years--;
                    testDate = fromDate.AddMonths(12 * years);
                }
    
                // Add months until we go too far.
                months = 0;
    
                while (testDate <= toDate)
                {
                    months++;
                    testDate = fromDate.AddMonths(12 * years + months);
                }
    
                months--;
    
                // Subtract to see how many more days,
                // hours, minutes, etc. we need.
                fromDate = fromDate.AddMonths(12 * years + months);
    
                TimeSpan remainder = toDate - fromDate;
    
                days = remainder.Days;
                hours = remainder.Hours;
                minutes = remainder.Minutes;
                seconds = remainder.Seconds;
                milliseconds = remainder.Milliseconds;
    
            }
        }
    
    }
    
    0 comments No comments