简体   繁体   English

有没有更聪明的方法来使用 DateTime 对象生成“时间以来”

[英]is there a smarter way to generate "time since" with a DateTime objects

i have this code to take a time in the past and generate a readable string to represent how long ago it was.我有这段代码在过去花一些时间并生成一个可读的字符串来表示它是多久以前。

  1. I would have thought Timespan.Hours would give you hours even if its multiple daye in the past but it looks like it breaks it down into its seperate components (days, months, etc).我原以为 Timespan.Hours 会给你几个小时,即使它在过去多天,但它看起来像是将其分解为单独的组件(天、月等)。 How would i get total hours ago (even if its more than 1 day?我将如何获得总小时数(即使超过 1 天?

  2. Is there any cleaner way to write this type of code below as it seems pretty spagetti-ish.有没有什么更简洁的方法可以在下面编写这种类型的代码,因为它看起来很像意大利面条。

Here is the code这是代码

        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;
        }

Use the TotalHours property or other Total[TimeUnit] properties in the timespan object.在时间跨度对象中使用TotalHours属性或其他Total[TimeUnit]属性。

For a timespan of 1:10 (hh:mm), it equates to 1 Hours and 10 Minutes or 1.167 TotalHours and 70 TotalMinutes .对于 1:10 (hh:mm) 的时间跨度,它等于 1 Hours 10 Minutes或 1.167 TotalHours和 70 TotalMinutes


As for cleaning it up, stick to using if/else branches as you had earlier.至于清理它,请像之前一样坚持使用 if/else 分支。 switch/case will not help you with these conditions, only for specific values. switch/case 不会帮助您解决这些条件,仅适用于特定值。 Something like this:像这样的东西:

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 and up, you could use switch expressions and property patterns to condense it further to a single expression. 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",
};

A very late answer, but I felt the need for this, and searching for common JS terms such as "C# momentjs datetime" or "C# timeago" showed results which were not at all helpful - I don't want to maintain extra code with hardcoded magic numbers and which won't be localization-friendly.一个很晚的答案,但我觉得有必要这样做,并且搜索常见的 JS 术语(例如“C# momentjs datetime”或“C# timeago”)显示的结果根本没有帮助 - 我不想用硬编码的幻数,并且对本地化不友好。 So, finally, in one of the comments in another SO answer, I found the library:所以,最后,在另一个 SO 答案的评论中,我找到了图书馆:

Humanizer for .NET - https://github.com/Humanizr/Humanizer#humanize-datetime .NET 的 Humanizer - https://github.com/Humanizr/Humanizer#humanize-datetime

Usage:用法:

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

And it's localizable too!而且它也可以本地化!

I know this is an old post, but I came up with this solution using recursion after searching for this topic and reading Jeff Mercado's answer我知道这是一篇旧帖子,但在搜索此主题并阅读 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;
}

used as such如此使用

var tspan = DateTime.Now.Subtract(reqDate);
string how_long_ago = PeriodOfTimeOutput(tspan);

As an alternative, I have a solution that does that beyond days with weeks, months and years.作为替代方案,我有一个解决方案,可以在数周、数月和数年的时间里做到这一点。 The approach is a bit different It advances from the past to the future, first trying the big steps and if it overshoots switching to the next smaller one.方法有点不同 它从过去走向未来,首先尝试大的步骤,如果它过冲,则切换到下一个较小的步骤。

PeriodOfTimeOutput.cs PeriodOfTimeOutput.cs

If you want more flexibility and smarter-looking outcome, then there is an extension method for this in the Olive framework named ToTimeDifferenceString() .如果您想要更大的灵活性和更智能的结果,那么Olive 框架中有一个名为ToTimeDifferenceString()的扩展方法。

It has a parameter named precisionParts.它有一个名为 precisionParts 的参数。 For example:例如:

myDate.ToTimeDifferenceString(1)

which returns "2 days ago"返回“2天前”

or或者

myDate.ToTimeDifferenceString(2)

which returns "2 days and 4 hours ago"返回“2天4小时前”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM