Calculate relative time in C#

后端 未结 30 2196
生来不讨喜
生来不讨喜 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条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-11-21 06:22

    I thought I'd give this a shot using classes and polymorphism. I had a previous iteration which used sub-classing which ended up having way too much overhead. I've switched to a more flexible delegate / public property object model which is significantly better. My code is very slightly more accurate, I wish I could come up with a better way to generate "months ago" that didn't seem too over-engineered.

    I think I'd still stick with Jeff's if-then cascade because it's less code and it's simpler (it's definitely easier to ensure it'll work as expected).

    For the below code PrintRelativeTime.GetRelativeTimeMessage(TimeSpan ago) returns the relative time message (e.g. "yesterday").

    public class RelativeTimeRange : IComparable
    {
        public TimeSpan UpperBound { get; set; }
    
        public delegate string RelativeTimeTextDelegate(TimeSpan timeDelta);
    
        public RelativeTimeTextDelegate MessageCreator { get; set; }
    
        public int CompareTo(object obj)
        {
            if (!(obj is RelativeTimeRange))
            {
                return 1;
            }
            // note that this sorts in reverse order to the way you'd expect, 
            // this saves having to reverse a list later
            return (obj as RelativeTimeRange).UpperBound.CompareTo(UpperBound);
        }
    }
    
    public class PrintRelativeTime
    {
        private static List timeRanges;
    
        static PrintRelativeTime()
        {
            timeRanges = new List{
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.FromSeconds(1),
                    MessageCreator = (delta) => 
                    { return "one second ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.FromSeconds(60),
                    MessageCreator = (delta) => 
                    { return delta.Seconds + " seconds ago"; }
    
                }, 
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.FromMinutes(2),
                    MessageCreator = (delta) => 
                    { return "one minute ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.FromMinutes(60),
                    MessageCreator = (delta) => 
                    { return delta.Minutes + " minutes ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.FromHours(2),
                    MessageCreator = (delta) => 
                    { return "one hour ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.FromHours(24),
                    MessageCreator = (delta) => 
                    { return delta.Hours + " hours ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.FromDays(2),
                    MessageCreator = (delta) => 
                    { return "yesterday"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = DateTime.Now.Subtract(DateTime.Now.AddMonths(-1)),
                    MessageCreator = (delta) => 
                    { return delta.Days + " days ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = DateTime.Now.Subtract(DateTime.Now.AddMonths(-2)),
                    MessageCreator = (delta) => 
                    { return "one month ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = DateTime.Now.Subtract(DateTime.Now.AddYears(-1)),
                    MessageCreator = (delta) => 
                    { return (int)Math.Floor(delta.TotalDays / 30) + " months ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = DateTime.Now.Subtract(DateTime.Now.AddYears(-2)),
                    MessageCreator = (delta) => 
                    { return "one year ago"; }
                }, 
                new RelativeTimeRange
                {
                    UpperBound = TimeSpan.MaxValue,
                    MessageCreator = (delta) => 
                    { return (int)Math.Floor(delta.TotalDays / 365.24D) + " years ago"; }
                }
            };
    
            timeRanges.Sort();
        }
    
        public static string GetRelativeTimeMessage(TimeSpan ago)
        {
            RelativeTimeRange postRelativeDateRange = timeRanges[0];
    
            foreach (var timeRange in timeRanges)
            {
                if (ago.CompareTo(timeRange.UpperBound) <= 0)
                {
                    postRelativeDateRange = timeRange;
                }
            }
    
            return postRelativeDateRange.MessageCreator(ago);
        }
    }
    

提交回复
热议问题