引言:为什么我们需要“相对时间”?
\n\n您是否曾想过,为什么社交网络和新闻网站会写“2小时前”或“昨天”,而不是“25.04.2025 14:32”?因为我们的大脑处理相对时间要快得多。绝对日期需要分析:“好吧,今天是25号,那意味着是……”。相对日期则能瞬间给出答案。
\n\n如果您正在使用C#进行开发——无论是ASP.NET的Web应用程序、桌面应用程序还是Telegram机器人——迟早您都需要向用户展示“刚刚”、“3分钟前”或“大约一年前”这样的时间格式。在Stack Overflow上,“Calculate relative time in C#”这个问题获得了数千次浏览,这意味着这是开发人员的一个真实痛点。
\n\n在本文中,我们将分析最正确且最灵活的方法来计算C#中的相对时间。您将获得可以直接插入项目的现成代码,理解其工作原理,并了解如何根据任何需求对其进行自定义。
\n\n问题:简单的日期减法有什么问题?
\n\n首先想到的是从一个日期中减去另一个日期,得到TimeSpan。是的,这可行。但魔鬼藏在细节中:
- \n
- 阈值。“分钟”何时结束,“小时”何时开始?而“小时”又何时过渡到“天”? \n
- 未来日期。如果日期在未来怎么办?显示“5分钟后”还是“1天后”? \n
- 代码可读性。如果您将逻辑分散在整个项目中,一个月后您自己都会搞混。 \n
因此,我们需要的不仅仅是一段代码,而是一个统一的、可重用的方法。
\n\n解决方案:用于计算相对时间的通用方法
\n\n最好的方法是编写一个静态方法,它接受DateTime(或DateTimeOffset)并返回一个漂亮的字符串。以下是一个基础但已经非常强大的实现,可以在Stack Overflow的讨论中找到并根据自己的需求进行调整:
using System;\n\npublic static class TimeHelper\n{\n public static string GetRelativeTime(DateTime dateTime)\n {\n var now = DateTime.Now;\n var utcNow = DateTime.UtcNow;\n\n // 重要:在同一个时区进行比较!\n var timeSpan = now - dateTime;\n\n // 情况1:未来日期\n if (timeSpan.TotalSeconds < 0)\n {\n // 为未来计算绝对值\n timeSpan = timeSpan.Duration();\n if (timeSpan.TotalMinutes < 1)\n return "几秒后";\n if (timeSpan.TotalMinutes < 60)\n return $"在 {timeSpan.Minutes} 分钟后";\n if (timeSpan.TotalHours < 24)\n return $"在 {timeSpan.Hours} 小时后";\n if (timeSpan.TotalDays < 30)\n return $"在 {timeSpan.Days} 天后";\n if (timeSpan.TotalDays < 365)\n return $"在 {timeSpan.Days / 30} 个月后";\n return $"在 {timeSpan.Days / 365} 年后";\n }\n\n // 情况2:过去\n if (timeSpan.TotalMinutes < 1)\n return "刚刚";\n if (timeSpan.TotalMinutes < 60)\n return $"{timeSpan.Minutes} 分钟前";\n if (timeSpan.TotalHours < 24)\n return $"{timeSpan.Hours} 小时前";\n if (timeSpan.TotalDays < 7)\n return $"{timeSpan.Days} 天前";\n\n // 对于超过一周的日期,使用天数\n if (timeSpan.TotalDays < 30)\n return $"{(int)timeSpan.TotalDays} 天前";\n if (timeSpan.TotalDays < 365)\n {\n int months = (int)(timeSpan.TotalDays / 30);\n return $"{months} 个月前";\n }\n\n int years = (int)(timeSpan.TotalDays / 365);\n return $"{years} 年