给定特定的DateTime值,如何显示相对时间,例如:
2小时前3天前一个月前
给定特定的DateTime值,如何显示相对时间,例如:
2小时前3天前一个月前
当前回答
@杰夫
var ts=新时间跨度(DateTime.UtcNow.Ticks-dt.Ticks);
对DateTime执行减法仍会返回TimeSpan。
所以你可以这样做
(DateTime.UtcNow - dt).TotalSeconds
我也很惊讶地看到常数用手相乘,然后注释加上乘法。这是错误的优化吗?
其他回答
我想我应该用类和多态性来尝试一下。我以前的迭代使用了子类,结果开销太大。我已经切换到一个更灵活的委托/公共属性对象模型,这明显更好。我的代码稍微准确一点,我希望我能想出一种更好的方法来生成“几个月前”的代码,而这种方法看起来并没有过度设计。
我想我还是会坚持Jeff的if-then-cascade,因为它的代码更少,而且更简单(肯定更容易确保它按预期工作)。
对于以下代码,PrintRelativeTime.GetRelativeTime message(TimeSpan ago)返回相对时间消息(例如“昨天”)。
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<RelativeTimeRange> timeRanges;
static PrintRelativeTime()
{
timeRanges = new List<RelativeTimeRange>{
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);
}
}
@杰夫
我知道你的有点长。然而,随着对“昨天”和“几年”的支持,它似乎确实更为有力。但根据我的经验,当使用此选项时,用户最有可能在前30天内查看内容。只有真正的铁杆人才会在这之后出现。所以,我通常选择保持简短。
这是我目前在我的一个网站上使用的方法。这只返回相对的日期、小时和时间。然后用户必须在输出中加上“ago”。
public static string ToLongString(this TimeSpan time)
{
string output = String.Empty;
if (time.Days > 0)
output += time.Days + " days ";
if ((time.Days == 0 || time.Days == 1) && time.Hours > 0)
output += time.Hours + " hr ";
if (time.Days == 0 && time.Minutes > 0)
output += time.Minutes + " min ";
if (output.Length == 0)
output += time.Seconds + " sec";
return output.Trim();
}
以某种方式,您可以使用DateTime函数以秒到年计算相对时间,请尝试以下操作:
using System;
public class Program {
public static string getRelativeTime(DateTime past) {
DateTime now = DateTime.Today;
string rt = "";
int time;
string statement = "";
if (past.Second >= now.Second) {
if (past.Second - now.Second == 1) {
rt = "second ago";
}
rt = "seconds ago";
time = past.Second - now.Second;
statement = "" + time;
return (statement + rt);
}
if (past.Minute >= now.Minute) {
if (past.Second - now.Second == 1) {
rt = "second ago";
} else {
rt = "minutes ago";
}
time = past.Minute - now.Minute;
statement = "" + time;
return (statement + rt);
}
// This process will go on until years
}
public static void Main() {
DateTime before = new DateTime(1995, 8, 24);
string date = getRelativeTime(before);
Console.WriteLine("Windows 95 was {0}.", date);
}
}
不完全有效,但如果您对其进行一点修改和调试,它很可能会完成任务。
jquery.timeago插件
Jeff,因为Stack Overflow广泛使用jQuery,所以我建议使用jQuery.timeago插件。
优点:
即使页面是在10分钟前打开的,也不要使用“1分钟前”的时间戳;timeago自动刷新。您可以充分利用web应用程序中的页面和/或片段缓存,因为时间戳不是在服务器上计算的。你可以像酷孩子一样使用微格式。
只需将其附加到DOM就绪的时间戳:
jQuery(document).ready(function() {
jQuery('abbr.timeago').timeago();
});
这将在标题中使用timeago类和ISO 8601时间戳转换所有缩写元素:
<abbr class="timeago" title="2008-07-17T09:24:17Z">July 17, 2008</abbr>
变成这样:
<abbr class="timeago" title="July 17, 2008">4 months ago</abbr>
结果:4个月前。随着时间的推移,时间戳将自动更新。
免责声明:我写了这个插件,所以我有偏见。
使用Fluent DateTime
var dateTime1 = 2.Hours().Ago();
var dateTime2 = 3.Days().Ago();
var dateTime3 = 1.Months().Ago();
var dateTime4 = 5.Hours().FromNow();
var dateTime5 = 2.Weeks().FromNow();
var dateTime6 = 40.Seconds().FromNow();