Calculate relative time in C#

后端 未结 30 2182
生来不讨喜
生来不讨喜 2020-11-21 05:59

Given a specific DateTime value, how do I display relative time, like:

  • 2 hours ago
  • 3 days ago
  • a month ago
相关标签:
30条回答
  • 2020-11-21 06:24

    A couple of years late to the party, but I had a requirement to do this for both past and future dates, so I combined Jeff's and Vincent's into this. It's a ternarytastic extravaganza! :)

    public static class DateTimeHelper
        {
            private const int SECOND = 1;
            private const int MINUTE = 60 * SECOND;
            private const int HOUR = 60 * MINUTE;
            private const int DAY = 24 * HOUR;
            private const int MONTH = 30 * DAY;
    
            /// <summary>
            /// Returns a friendly version of the provided DateTime, relative to now. E.g.: "2 days ago", or "in 6 months".
            /// </summary>
            /// <param name="dateTime">The DateTime to compare to Now</param>
            /// <returns>A friendly string</returns>
            public static string GetFriendlyRelativeTime(DateTime dateTime)
            {
                if (DateTime.UtcNow.Ticks == dateTime.Ticks)
                {
                    return "Right now!";
                }
    
                bool isFuture = (DateTime.UtcNow.Ticks < dateTime.Ticks);
                var ts = DateTime.UtcNow.Ticks < dateTime.Ticks ? new TimeSpan(dateTime.Ticks - DateTime.UtcNow.Ticks) : new TimeSpan(DateTime.UtcNow.Ticks - dateTime.Ticks);
    
                double delta = ts.TotalSeconds;
    
                if (delta < 1 * MINUTE)
                {
                    return isFuture ? "in " + (ts.Seconds == 1 ? "one second" : ts.Seconds + " seconds") : ts.Seconds == 1 ? "one second ago" : ts.Seconds + " seconds ago";
                }
                if (delta < 2 * MINUTE)
                {
                    return isFuture ? "in a minute" : "a minute ago";
                }
                if (delta < 45 * MINUTE)
                {
                    return isFuture ? "in " + ts.Minutes + " minutes" : ts.Minutes + " minutes ago";
                }
                if (delta < 90 * MINUTE)
                {
                    return isFuture ? "in an hour" : "an hour ago";
                }
                if (delta < 24 * HOUR)
                {
                    return isFuture ? "in " + ts.Hours + " hours" : ts.Hours + " hours ago";
                }
                if (delta < 48 * HOUR)
                {
                    return isFuture ? "tomorrow" : "yesterday";
                }
                if (delta < 30 * DAY)
                {
                    return isFuture ? "in " + ts.Days + " days" : ts.Days + " days ago";
                }
                if (delta < 12 * MONTH)
                {
                    int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
                    return isFuture ? "in " + (months <= 1 ? "one month" : months + " months") : months <= 1 ? "one month ago" : months + " months ago";
                }
                else
                {
                    int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
                    return isFuture ? "in " + (years <= 1 ? "one year" : years + " years") : years <= 1 ? "one year ago" : years + " years ago";
                }
            }
        }
    
    0 讨论(0)
  • 2020-11-21 06:24

    Given the world and her husband appear to be posting code samples, here is what I wrote a while ago, based on a couple of these answers.

    I had a specific need for this code to be localisable. So I have two classes — Grammar, which specifies the localisable terms, and FuzzyDateExtensions, which holds a bunch of extension methods. I had no need to deal with future datetimes, so no attempt is made to handle them with this code.

    I've left some of the XMLdoc in the source, but removed most (where they'd be obvious) for brevity's sake. I've also not included every class member here:

    public class Grammar
    {
        /// <summary> Gets or sets the term for "just now". </summary>
        public string JustNow { get; set; }
        /// <summary> Gets or sets the term for "X minutes ago". </summary>
        /// <remarks>
        ///     This is a <see cref="String.Format"/> pattern, where <c>{0}</c>
        ///     is the number of minutes.
        /// </remarks>
        public string MinutesAgo { get; set; }
        public string OneHourAgo { get; set; }
        public string HoursAgo { get; set; }
        public string Yesterday { get; set; }
        public string DaysAgo { get; set; }
        public string LastMonth { get; set; }
        public string MonthsAgo { get; set; }
        public string LastYear { get; set; }
        public string YearsAgo { get; set; }
        /// <summary> Gets or sets the term for "ages ago". </summary>
        public string AgesAgo { get; set; }
    
        /// <summary>
        ///     Gets or sets the threshold beyond which the fuzzy date should be
        ///     considered "ages ago".
        /// </summary>
        public TimeSpan AgesAgoThreshold { get; set; }
    
        /// <summary>
        ///     Initialises a new <see cref="Grammar"/> instance with the
        ///     specified properties.
        /// </summary>
        private void Initialise(string justNow, string minutesAgo,
            string oneHourAgo, string hoursAgo, string yesterday, string daysAgo,
            string lastMonth, string monthsAgo, string lastYear, string yearsAgo,
            string agesAgo, TimeSpan agesAgoThreshold)
        { ... }
    }
    

    The FuzzyDateString class contains:

    public static class FuzzyDateExtensions
    {
        public static string ToFuzzyDateString(this TimeSpan timespan)
        {
            return timespan.ToFuzzyDateString(new Grammar());
        }
    
        public static string ToFuzzyDateString(this TimeSpan timespan,
            Grammar grammar)
        {
            return GetFuzzyDateString(timespan, grammar);
        }
    
        public static string ToFuzzyDateString(this DateTime datetime)
        {
            return (DateTime.Now - datetime).ToFuzzyDateString();
        }
    
        public static string ToFuzzyDateString(this DateTime datetime,
           Grammar grammar)
        {
            return (DateTime.Now - datetime).ToFuzzyDateString(grammar);
        }
    
    
        private static string GetFuzzyDateString(TimeSpan timespan,
           Grammar grammar)
        {
            timespan = timespan.Duration();
    
            if (timespan >= grammar.AgesAgoThreshold)
            {
                return grammar.AgesAgo;
            }
    
            if (timespan < new TimeSpan(0, 2, 0))    // 2 minutes
            {
                return grammar.JustNow;
            }
    
            if (timespan < new TimeSpan(1, 0, 0))    // 1 hour
            {
                return String.Format(grammar.MinutesAgo, timespan.Minutes);
            }
    
            if (timespan < new TimeSpan(1, 55, 0))    // 1 hour 55 minutes
            {
                return grammar.OneHourAgo;
            }
    
            if (timespan < new TimeSpan(12, 0, 0)    // 12 hours
                && (DateTime.Now - timespan).IsToday())
            {
                return String.Format(grammar.HoursAgo, timespan.RoundedHours());
            }
    
            if ((DateTime.Now.AddDays(1) - timespan).IsToday())
            {
                return grammar.Yesterday;
            }
    
            if (timespan < new TimeSpan(32, 0, 0, 0)    // 32 days
                && (DateTime.Now - timespan).IsThisMonth())
            {
                return String.Format(grammar.DaysAgo, timespan.RoundedDays());
            }
    
            if ((DateTime.Now.AddMonths(1) - timespan).IsThisMonth())
            {
                return grammar.LastMonth;
            }
    
            if (timespan < new TimeSpan(365, 0, 0, 0, 0)    // 365 days
                && (DateTime.Now - timespan).IsThisYear())
            {
                return String.Format(grammar.MonthsAgo, timespan.RoundedMonths());
            }
    
            if ((DateTime.Now - timespan).AddYears(1).IsThisYear())
            {
                return grammar.LastYear;
            }
    
            return String.Format(grammar.YearsAgo, timespan.RoundedYears());
        }
    }
    

    One of the key things I wanted to achieve, as well as localisation, was that "today" would only mean "this calendar day", so the IsToday, IsThisMonth, IsThisYear methods look like this:

    public static bool IsToday(this DateTime date)
    {
        return date.DayOfYear == DateTime.Now.DayOfYear && date.IsThisYear();
    }
    

    and the rounding methods are like this (I've included RoundedMonths, as that's a bit different):

    public static int RoundedDays(this TimeSpan timespan)
    {
        return (timespan.Hours > 12) ? timespan.Days + 1 : timespan.Days;
    }
    
    public static int RoundedMonths(this TimeSpan timespan)
    {
        DateTime then = DateTime.Now - timespan;
    
        // Number of partial months elapsed since 1 Jan, AD 1 (DateTime.MinValue)
        int nowMonthYears = DateTime.Now.Year * 12 + DateTime.Now.Month;
        int thenMonthYears = then.Year * 12 + then.Month;                    
    
        return nowMonthYears - thenMonthYears;
    }
    

    I hope people find this useful and/or interesting :o)

    0 讨论(0)
  • 2020-11-21 06:26

    you can try this.I think it will work correctly.

    long delta = new Date().getTime() - date.getTime();
    const int SECOND = 1;
    const int MINUTE = 60 * SECOND;
    const int HOUR = 60 * MINUTE;
    const int DAY = 24 * HOUR;
    const int MONTH = 30 * DAY;
    
    if (delta < 0L)
    {
      return "not yet";
    }
    if (delta < 1L * MINUTE)
    {
      return ts.Seconds == 1 ? "one second ago" : ts.Seconds + " seconds ago";
    }
    if (delta < 2L * MINUTE)
    {
      return "a minute ago";
    }
    if (delta < 45L * MINUTE)
    {
      return ts.Minutes + " minutes ago";
    }
    if (delta < 90L * MINUTE)
    {
      return "an hour ago";
    }
    if (delta < 24L * HOUR)
    {
      return ts.Hours + " hours ago";
    }
    if (delta < 48L * HOUR)
    {
      return "yesterday";
    }
    if (delta < 30L * DAY)
    {
      return ts.Days + " days ago";
    }
    if (delta < 12L * MONTH)
    {
      int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
      return months <= 1 ? "one month ago" : months + " months ago";
    }
    else
    {
      int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
      return years <= 1 ? "one year ago" : years + " years ago";
    }
    
    0 讨论(0)
  • 2020-11-21 06:26

    I think there is already a number of answers related to this post, but one can use this which is easy to use just like plugin and also easily readable for programmers. Send your specific date, and get its value in string form:

    public string RelativeDateTimeCount(DateTime inputDateTime)
    {
        string outputDateTime = string.Empty;
        TimeSpan ts = DateTime.Now - inputDateTime;
    
        if (ts.Days > 7)
        { outputDateTime = inputDateTime.ToString("MMMM d, yyyy"); }
    
        else if (ts.Days > 0)
        {
            outputDateTime = ts.Days == 1 ? ("about 1 Day ago") : ("about " + ts.Days.ToString() + " Days ago");
        }
        else if (ts.Hours > 0)
        {
            outputDateTime = ts.Hours == 1 ? ("an hour ago") : (ts.Hours.ToString() + " hours ago");
        }
        else if (ts.Minutes > 0)
        {
            outputDateTime = ts.Minutes == 1 ? ("1 minute ago") : (ts.Minutes.ToString() + " minutes ago");
        }
        else outputDateTime = "few seconds ago";
    
        return outputDateTime;
    }
    
    0 讨论(0)
  • 2020-11-21 06:27

    Here's how I do it

    var ts = new TimeSpan(DateTime.UtcNow.Ticks - dt.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";
    

    Suggestions? Comments? Ways to improve this algorithm?

    0 讨论(0)
  • 2020-11-21 06:28

    iPhone Objective-C Version

    + (NSString *)timeAgoString:(NSDate *)date {
        int delta = -(int)[date timeIntervalSinceNow];
    
        if (delta < 60)
        {
            return delta == 1 ? @"one second ago" : [NSString stringWithFormat:@"%i seconds ago", delta];
        }
        if (delta < 120)
        {
            return @"a minute ago";
        }
        if (delta < 2700)
        {
            return [NSString stringWithFormat:@"%i minutes ago", delta/60];
        }
        if (delta < 5400)
        {
            return @"an hour ago";
        }
        if (delta < 24 * 3600)
        {
            return [NSString stringWithFormat:@"%i hours ago", delta/3600];
        }
        if (delta < 48 * 3600)
        {
            return @"yesterday";
        }
        if (delta < 30 * 24 * 3600)
        {
            return [NSString stringWithFormat:@"%i days ago", delta/(24*3600)];
        }
        if (delta < 12 * 30 * 24 * 3600)
        {
            int months = delta/(30*24*3600);
            return months <= 1 ? @"one month ago" : [NSString stringWithFormat:@"%i months ago", months];
        }
        else
        {
            int years = delta/(12*30*24*3600);
            return years <= 1 ? @"one year ago" : [NSString stringWithFormat:@"%i years ago", years];
        }
    }
    
    0 讨论(0)
提交回复
热议问题