10

我有这段代码在过去需要一段时间并生成一个可读的字符串来表示它是多久以前的。

  1. 我原以为 Timespan.Hours 会给你几个小时,即使它过去多天,但看起来它把它分解成单独的部分(天、月等)。我如何获得总小时数(即使超过 1 天?

  2. 有没有更简洁的方法可以在下面编写这种类型的代码,因为它看起来很意大利面。

这是代码

        DateTime when = GetDateTimeinPast();
        TimeSpan ts = DateTime.Now.Subtract(when);

        switch (ts.Days)
        {
            case 0:
               if (ts.Hours < 1)
                    b.Append( ts.Minutes + " minutes ago");
               else
                   b.Append( ts.Hours + " hours ago");
                break;
            case 1:
                b.Append( " yesterday");
                break;
            case 2:
            case 3:                
            case 4:

                b.Append( "on " + when.DayOfWeek.ToString());
                break;
            default:
                b.Append(ts.Days + " days ago");
                break;
        }
4

5 回答 5

18

使用时间跨度对象中的TotalHours属性或其他Total[TimeUnit]属性。

对于 1:10 (hh:mm) 的时间跨度,它等于 1Hours和 10Minutes或 1.167TotalHours和 70 TotalMinutes


至于清理它,请像之前一样坚持使用 if/else 分支。switch/case 不会帮助您处理这些条件,仅适用于特定值。像这样的东西:

DateTime when = GetDateTimeinPast();
TimeSpan ts = DateTime.Now.Subtract(when);
if (ts.TotalHours < 1)
    b.AppendFormat("{0} minutes ago", (int)ts.TotalMinutes);
else if (ts.TotalDays < 1)
    b.AppendFormat("{0} hours ago", (int)ts.TotalHours);
//etc...

C# 8 及更高版本,您可以使用 switch 表达式和属性模式将其进一步压缩为单个表达式。

(DateTime.Now - when) switch
{
    { TotalHours: < 1 } ts => $"{ts.Minutes} minutes ago",
    { TotalDays: < 1 } ts => $"{ts.Hours} hours ago",
    { TotalDays: < 2 } => $"yesterday",
    { TotalDays: < 5 } => $"on {when.DayOfWeek}",
    var ts => $"{ts.Days} days ago",
};
于 2010-08-01T19:48:29.140 回答
3

一个很晚的答案,但我觉得有必要这样做,并且搜索常见的 JS 术语,如“C# momentjs datetime”或“C# timeago”显示的结果根本没有帮助 - 我不想维护额外的代码硬编码的幻数,这对本地化不友好。所以,最后,在另一个 SO 答案中的一个评论中,我找到了这个库:

.NET 的人性化程序 - https://github.com/Humanizr/Humanizer#humanize-datetime

用法:

DateTime.UtcNow.AddHours(-2).Humanize() => "2 hours ago"

它也是可本地化的!

于 2017-05-27T23:47:48.747 回答
1

作为替代方案,我有一个解决方案,它可以超越数周、数月和数年的天数。方法有点不同,它从过去推进到未来,首先尝试大步骤,如果超过了则切换到下一个较小的步骤。

PeriodOfTimeOutput.cs

于 2010-08-01T21:53:44.793 回答
1

我知道这是一篇旧帖子,但在搜索此主题并阅读 Jeff Mercado 的答案后,我使用递归提出了此解决方案

private string PeriodOfTimeOutput(TimeSpan tspan, int level = 0)
{
    string how_long_ago = "ago";
    if (level >= 2) return how_long_ago;
    if (tspan.Days > 1)
        how_long_ago = string.Format("{0} Days ago", tspan.Days);
    else if (tspan.Days == 1)
        how_long_ago = string.Format("1 Day {0}", PeriodOfTimeOutput(new TimeSpan(tspan.Hours, tspan.Minutes, tspan.Seconds), level + 1));
    else if (tspan.Hours >= 1)
        how_long_ago = string.Format("{0} {1} {2}", tspan.Hours, (tspan.Hours > 1) ? "Hours" : "Hour", PeriodOfTimeOutput(new TimeSpan(0, tspan.Minutes, tspan.Seconds), level + 1));
    else if (tspan.Minutes >= 1)
        how_long_ago = string.Format("{0} {1} {2}", tspan.Minutes, (tspan.Minutes > 1) ? "Minutes" : "Minute", PeriodOfTimeOutput(new TimeSpan(0, 0, tspan.Seconds), level + 1));
    else if (tspan.Seconds >= 1)
        how_long_ago = string.Format("{0} {1} ago", tspan.Seconds, (tspan.Seconds > 1) ? "Seconds" : "Second");        
    return how_long_ago;
}

像这样使用

var tspan = DateTime.Now.Subtract(reqDate);
string how_long_ago = PeriodOfTimeOutput(tspan);
于 2015-11-12T16:02:32.743 回答
1

如果您想要更大的灵活性和更智能的结果,那么Olive 框架中有一个名为ToTimeDifferenceString()的扩展方法。

它有一个名为precisionParts 的参数。例如:

myDate.ToTimeDifferenceString(1)

返回“2天前”

或者

myDate.ToTimeDifferenceString(2)

返回“2天4小时前”

于 2018-03-22T14:13:34.450 回答