Calculate relative time in C#
给定一个特定的
- 2小时前
- 3天前
- 一个月前
Jeff,您的代码很好,但是可以用常量更清晰(如代码完整部分中建议的那样)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | const int SECOND = 1; const int MINUTE = 60 * SECOND; const int HOUR = 60 * MINUTE; const int DAY = 24 * HOUR; const int MONTH = 30 * DAY; var ts = new TimeSpan(DateTime.UtcNow.Ticks - yourDate.Ticks); double delta = Math.Abs(ts.TotalSeconds); if (delta < 1 * MINUTE) return ts.Seconds == 1 ?"one second ago" : ts.Seconds +" seconds ago"; if (delta < 2 * MINUTE) return"a minute ago"; if (delta < 45 * MINUTE) return ts.Minutes +" minutes ago"; if (delta < 90 * MINUTE) return"an hour ago"; if (delta < 24 * HOUR) return ts.Hours +" hours ago"; if (delta < 48 * HOUR) return"yesterday"; if (delta < 30 * DAY) return ts.Days +" days ago"; if (delta < 12 * MONTH) { int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); return months <= 1 ?"one month ago" : months +" months ago"; } else { int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); return years <= 1 ?"one year ago" : years +" years ago"; } |
jquery.timeago插件
杰夫,因为堆栈溢出广泛使用jquery,所以我推荐jquery.timeago插件。
效益:
- 避免使用日期为"1分钟前"的时间戳,即使该页是10分钟前打开的;TimeAgo会自动刷新。
- 您可以充分利用Web应用程序中的页面和/或片段缓存,因为时间戳不是在服务器上计算的。
- 你可以像酷孩子一样使用微格式。
只需将它附加到DOM上的时间戳上即可:
1 2 3 | jQuery(document).ready(function() { jQuery('abbr.timeago').timeago(); }); |
这将使所有
1 | July 17, 2008</abbr> |
变成这样:
1 | 4 months ago</abbr> |
收益率:4个月前。随着时间的推移,时间戳将自动更新。
免责声明:我写了这个插件,所以我有偏见。
我就是这么做的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | var ts = new TimeSpan(DateTime.UtcNow.Ticks - dt.Ticks); double delta = Math.Abs(ts.TotalSeconds); if (delta < 60) { return ts.Seconds == 1 ?"one second ago" : ts.Seconds +" seconds ago"; } if (delta < 120) { return"a minute ago"; } if (delta < 2700) // 45 * 60 { return ts.Minutes +" minutes ago"; } if (delta < 5400) // 90 * 60 { return"an hour ago"; } if (delta < 86400) // 24 * 60 * 60 { return ts.Hours +" hours ago"; } if (delta < 172800) // 48 * 60 * 60 { return"yesterday"; } if (delta < 2592000) // 30 * 24 * 60 * 60 { return ts.Days +" days ago"; } if (delta < 31104000) // 12 * 30 * 24 * 60 * 60 { int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); return months <= 1 ?"one month ago" : months +" months ago"; } int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); return years <= 1 ?"one year ago" : years +" years ago"; |
建议?评论?如何改进这个算法?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public static string RelativeDate(DateTime theDate) { Dictionary<long, string> thresholds = new Dictionary<long, string>(); int minute = 60; int hour = 60 * minute; int day = 24 * hour; thresholds.Add(60,"{0} seconds ago"); thresholds.Add(minute * 2,"a minute ago"); thresholds.Add(45 * minute,"{0} minutes ago"); thresholds.Add(120 * minute,"an hour ago"); thresholds.Add(day,"{0} hours ago"); thresholds.Add(day * 2,"yesterday"); thresholds.Add(day * 30,"{0} days ago"); thresholds.Add(day * 365,"{0} months ago"); thresholds.Add(long.MaxValue,"{0} years ago"); long since = (DateTime.Now.Ticks - theDate.Ticks) / 10000000; foreach (long threshold in thresholds.Keys) { if (since < threshold) { TimeSpan t = new TimeSpan((DateTime.Now.Ticks - theDate.Ticks)); return string.Format(thresholds[threshold], (t.Days > 365 ? t.Days / 365 : (t.Days > 0 ? t.Days : (t.Hours > 0 ? t.Hours : (t.Minutes > 0 ? t.Minutes : (t.Seconds > 0 ? t.Seconds : 0))))).ToString()); } } return""; } |
我更喜欢这个版本,因为它简洁,并且能够添加新的勾号。这可以用
这里是一个从Jeffs脚本重写的PHP脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | define("SECOND", 1); define("MINUTE", 60 * SECOND); define("HOUR", 60 * MINUTE); define("DAY", 24 * HOUR); define("MONTH", 30 * DAY); function relativeTime($time) { $delta = time() - $time; if ($delta < 1 * MINUTE) { return $delta == 1 ?"one second ago" : $delta ." seconds ago"; } if ($delta < 2 * MINUTE) { return"a minute ago"; } if ($delta < 45 * MINUTE) { return floor($delta / MINUTE) ." minutes ago"; } if ($delta < 90 * MINUTE) { return"an hour ago"; } if ($delta < 24 * HOUR) { return floor($delta / HOUR) ." hours ago"; } if ($delta < 48 * HOUR) { return"yesterday"; } if ($delta < 30 * DAY) { return floor($delta / DAY) ." days ago"; } if ($delta < 12 * MONTH) { $months = floor($delta / DAY / 30); return $months <= 1 ?"one month ago" : $months ." months ago"; } else { $years = floor($delta / DAY / 365); return $years <= 1 ?"one year ago" : $years ." years ago"; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public static string ToRelativeDate(DateTime input) { TimeSpan oSpan = DateTime.Now.Subtract(input); double TotalMinutes = oSpan.TotalMinutes; string Suffix =" ago"; if (TotalMinutes < 0.0) { TotalMinutes = Math.Abs(TotalMinutes); Suffix =" from now"; } var aValue = new SortedList<double, Func<string>>(); aValue.Add(0.75, () =>"less than a minute"); aValue.Add(1.5, () =>"about a minute"); aValue.Add(45, () => string.Format("{0} minutes", Math.Round(TotalMinutes))); aValue.Add(90, () =>"about an hour"); aValue.Add(1440, () => string.Format("about {0} hours", Math.Round(Math.Abs(oSpan.TotalHours)))); // 60 * 24 aValue.Add(2880, () =>"a day"); // 60 * 48 aValue.Add(43200, () => string.Format("{0} days", Math.Floor(Math.Abs(oSpan.TotalDays)))); // 60 * 24 * 30 aValue.Add(86400, () =>"about a month"); // 60 * 24 * 60 aValue.Add(525600, () => string.Format("{0} months", Math.Floor(Math.Abs(oSpan.TotalDays / 30)))); // 60 * 24 * 365 aValue.Add(1051200, () =>"about a year"); // 60 * 24 * 365 * 2 aValue.Add(double.MaxValue, () => string.Format("{0} years", Math.Floor(Math.Abs(oSpan.TotalDays / 365)))); return aValue.First(n => TotalMinutes < n.Key).Value.Invoke() + Suffix; } |
http://refactormycode.com/codes/493-twitter-esque-relative-dates
C 6版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | static readonly sortedlist<double,func<timespan,string>>offsets=new sortedlist<double,func<timespan,string>>{_0.75,=>"不到一分钟<div class="suo-content">[collapse title=""]<ul><li>这是非常好的:)这是国际海事组织的重构,可以为扩展方法?词典等是对静态的只读一次,然后从后创建和引用?</li><li>纯。krome:stackoverflow.com /问题/我如何计算相对的T - zwnj &;& # 8203;IME / & hellip;</li><li>你可能要拉出来一个一场这样的字典,你churn减少instantiation和GC。你要到<wyn>Func<double></wyn><wyn>Func<string></wyn>相变。</li><li>在JavaScript中drzaus emuzf jsfiddle.net / /</li></ul>[/collapse]</div><hr><P>下面是我添加的一个实现,作为datetime类的扩展方法,它处理将来和过去的日期,并提供一个近似选项,允许您指定要查找的详细级别("3小时前"与"3小时、23分钟、12秒前"):</P>[cc lang="csharp"]using System.Text; /// <summary> /// Compares a supplied date to the current date and generates a friendly English /// comparison ("5 days ago","5 days from now") /// </summary> /// <param name="date">The date to convert</param> /// <param name="approximate">When off, calculate timespan down to the second. /// When on, approximate to the largest round unit of time.</param> /// <returns></returns> public static string ToRelativeDateString(this DateTime value, bool approximate) { StringBuilder sb = new StringBuilder(); string suffix = (value > DateTime.Now) ?" from now" :" ago"; TimeSpan timeSpan = new TimeSpan(Math.Abs(DateTime.Now.Subtract(value).Ticks)); if (timeSpan.Days > 0) { sb.AppendFormat("{0} {1}", timeSpan.Days, (timeSpan.Days > 1) ?"days" :"day"); if (approximate) return sb.ToString() + suffix; } if (timeSpan.Hours > 0) { sb.AppendFormat("{0}{1} {2}", (sb.Length > 0) ?"," : string.Empty, timeSpan.Hours, (timeSpan.Hours > 1) ?"hours" :"hour"); if (approximate) return sb.ToString() + suffix; } if (timeSpan.Minutes > 0) { sb.AppendFormat("{0}{1} {2}", (sb.Length > 0) ?"," : string.Empty, timeSpan.Minutes, (timeSpan.Minutes > 1) ?"minutes" :"minute"); if (approximate) return sb.ToString() + suffix; } if (timeSpan.Seconds > 0) { sb.AppendFormat("{0}{1} {2}", (sb.Length > 0) ?"," : string.Empty, timeSpan.Seconds, (timeSpan.Seconds > 1) ?"seconds" :"second"); if (approximate) return sb.ToString() + suffix; } if (sb.Length == 0) return"right now"; sb.Append(suffix); return sb.ToString(); } |
我也建议在客户端计算这个。减少服务器的工作。
以下是我使用的版本(来自Zach Leatherman)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | /* * Javascript Humane Dates * Copyright (c) 2008 Dean Landolt (deanlandolt.com) * Re-write by Zach Leatherman (zachleat.com) * * Adopted from the John Resig's pretty.js * at http://ejohn.org/blog/javascript-pretty-date * and henrah's proposed modification * at http://ejohn.org/blog/javascript-pretty-date/#comment-297458 * * Licensed under the MIT license. */ function humane_date(date_str){ var time_formats = [ [60, 'just now'], [90, '1 minute'], // 60*1.5 [3600, 'minutes', 60], // 60*60, 60 [5400, '1 hour'], // 60*60*1.5 [86400, 'hours', 3600], // 60*60*24, 60*60 [129600, '1 day'], // 60*60*24*1.5 [604800, 'days', 86400], // 60*60*24*7, 60*60*24 [907200, '1 week'], // 60*60*24*7*1.5 [2628000, 'weeks', 604800], // 60*60*24*(365/12), 60*60*24*7 [3942000, '1 month'], // 60*60*24*(365/12)*1.5 [31536000, 'months', 2628000], // 60*60*24*365, 60*60*24*(365/12) [47304000, '1 year'], // 60*60*24*365*1.5 [3153600000, 'years', 31536000], // 60*60*24*365*100, 60*60*24*365 [4730400000, '1 century'] // 60*60*24*365*100*1.5 ]; var time = ('' + date_str).replace(/-/g,"/").replace(/[TZ]/g,""), dt = new Date, seconds = ((dt - new Date(time) + (dt.getTimezoneOffset() * 60000)) / 1000), token = ' ago', i = 0, format; if (seconds < 0) { seconds = Math.abs(seconds); token = ''; } while (format = time_formats[i++]) { if (seconds < format[0]) { if (format.length == 2) { return format[1] + (i > 1 ? token : ''); // Conditional so we don't return Just Now Ago } else { return Math.round(seconds / format[2]) + ' ' + format[1] + (i > 1 ? token : ''); } } } // overflow for centuries if(seconds > 4730400000) return Math.round(seconds / 4730400000) + ' centuries' + token; return date_str; }; if(typeof jQuery != 'undefined') { jQuery.fn.humane_dates = function(){ return this.each(function(){ var date = humane_date(this.title); if(date && jQuery(this).text() != date) // don't modify the dom if we don't have to jQuery(this).text(date); }); }; } |
在Nuget上还有一个叫做Humanizer的包,它实际上工作得很好。
1 2 3 4 5 6 7 8 | DateTime.UtcNow.AddHours(-30).Humanize() =>"yesterday" DateTime.UtcNow.AddHours(-2).Humanize() =>"2 hours ago" DateTime.UtcNow.AddHours(30).Humanize() =>"tomorrow" DateTime.UtcNow.AddHours(2).Humanize() =>"2 hours from now" TimeSpan.FromMilliseconds(1299630020).Humanize() =>"2 weeks" TimeSpan.FromMilliseconds(1299630020).Humanize(3) =>"2 weeks, 1 day, 1 hour" |
斯科特·汉塞尔曼在他的博客上写了一篇文章
@杰夫
我看你的好像有点长。然而,在"昨天"和"几年"的支持下,它确实显得更加强大。但在我的经验中,当这个被使用的时候,这个人最有可能在前30天查看内容。只有那些真正的铁杆人物才会在那之后出现。所以这就是我通常选择保持简短和简单的原因。
这是我目前在一个网站上使用的方法。这只返回相对的天、小时和时间。然后用户必须在输出中加上"ago"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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(); } |
参加聚会晚了几年,但我有一个要求,在过去和将来都要这样做,所以我把杰夫和文森特的结合在一起。这是一场三重口味的盛会!:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | public static class DateTimeHelper { private const int SECOND = 1; private const int MINUTE = 60 * SECOND; private const int HOUR = 60 * MINUTE; private const int DAY = 24 * HOUR; private const int MONTH = 30 * DAY; /// <summary> /// Returns a friendly version of the provided DateTime, relative to now. E.g.:"2 days ago", or"in 6 months". /// </summary> /// <param name="dateTime">The DateTime to compare to Now</param> /// <returns>A friendly string</returns> public static string GetFriendlyRelativeTime(DateTime dateTime) { if (DateTime.UtcNow.Ticks == dateTime.Ticks) { return"Right now!"; } bool isFuture = (DateTime.UtcNow.Ticks < dateTime.Ticks); var ts = DateTime.UtcNow.Ticks < dateTime.Ticks ? new TimeSpan(dateTime.Ticks - DateTime.UtcNow.Ticks) : new TimeSpan(DateTime.UtcNow.Ticks - dateTime.Ticks); double delta = ts.TotalSeconds; if (delta < 1 * MINUTE) { return isFuture ?"in" + (ts.Seconds == 1 ?"one second" : ts.Seconds +" seconds") : ts.Seconds == 1 ?"one second ago" : ts.Seconds +" seconds ago"; } if (delta < 2 * MINUTE) { return isFuture ?"in a minute" :"a minute ago"; } if (delta < 45 * MINUTE) { return isFuture ?"in" + ts.Minutes +" minutes" : ts.Minutes +" minutes ago"; } if (delta < 90 * MINUTE) { return isFuture ?"in an hour" :"an hour ago"; } if (delta < 24 * HOUR) { return isFuture ?"in" + ts.Hours +" hours" : ts.Hours +" hours ago"; } if (delta < 48 * HOUR) { return isFuture ?"tomorrow" :"yesterday"; } if (delta < 30 * DAY) { return isFuture ?"in" + ts.Days +" days" : ts.Days +" days ago"; } if (delta < 12 * MONTH) { int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); return isFuture ?"in" + (months <= 1 ?"one month" : months +" months") : months <= 1 ?"one month ago" : months +" months ago"; } else { int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); return isFuture ?"in" + (years <= 1 ?"one year" : years +" years") : years <= 1 ?"one year ago" : years +" years ago"; } } } |
在Java中有一种简单的方法吗?
下面是我的快速和肮脏的Java解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import java.util.Date; import javax.management.timer.Timer; String getRelativeDate(Date date) { long delta = new Date().getTime() - date.getTime(); if (delta < 1L * Timer.ONE_MINUTE) { return toSeconds(delta) == 1 ?"one second ago" : toSeconds(delta) +" seconds ago"; } if (delta < 2L * Timer.ONE_MINUTE) { return"a minute ago"; } if (delta < 45L * Timer.ONE_MINUTE) { return toMinutes(delta) +" minutes ago"; } if (delta < 90L * Timer.ONE_MINUTE) { return"an hour ago"; } if (delta < 24L * Timer.ONE_HOUR) { return toHours(delta) +" hours ago"; } if (delta < 48L * Timer.ONE_HOUR) { return"yesterday"; } if (delta < 30L * Timer.ONE_DAY) { return toDays(delta) +" days ago"; } if (delta < 12L * 4L * Timer.ONE_WEEK) { // a month long months = toMonths(delta); return months <= 1 ?"one month ago" : months +" months ago"; } else { long years = toYears(delta); return years <= 1 ?"one year ago" : years +" years ago"; } } private long toSeconds(long date) { return date / 1000L; } private long toMinutes(long date) { return toSeconds(date) / 60L; } private long toHours(long date) { return toMinutes(date) / 60L; } private long toDays(long date) { return toHours(date) / 24L; } private long toMonths(long date) { return toDays(date) / 30L; } private long toYears(long date) { return toMonths(date) / 365L; } |
iPhone Objective-C版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | + (NSString *)timeAgoString:(NSDate *)date { int delta = -(int)[date timeIntervalSinceNow]; if (delta < 60) { return delta == 1 ? @"one second ago" : [NSString stringWithFormat:@"%i seconds ago", delta]; } if (delta < 120) { return @"a minute ago"; } if (delta < 2700) { return [NSString stringWithFormat:@"%i minutes ago", delta/60]; } if (delta < 5400) { return @"an hour ago"; } if (delta < 24 * 3600) { return [NSString stringWithFormat:@"%i hours ago", delta/3600]; } if (delta < 48 * 3600) { return @"yesterday"; } if (delta < 30 * 24 * 3600) { return [NSString stringWithFormat:@"%i days ago", delta/(24*3600)]; } if (delta < 12 * 30 * 24 * 3600) { int months = delta/(30*24*3600); return months <= 1 ? @"one month ago" : [NSString stringWithFormat:@"%i months ago", months]; } else { int years = delta/(12*30*24*3600); return years <= 1 ? @"one year ago" : [NSString stringWithFormat:@"%i years ago", years]; } } |
考虑到全世界和她丈夫似乎都在发布代码示例,下面是我不久前根据这些答案写的。
我有一个特定的需求,这个代码是可本地化的。所以我有两个类——
我在源代码中保留了一些xmldoc,但为了简洁起见删除了大部分(在它们很明显的地方)。我也不包括所有的班级成员:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public class Grammar { /// <summary> Gets or sets the term for"just now". </summary> public string JustNow { get; set; } /// <summary> Gets or sets the term for"X minutes ago". </summary> /// <remarks> /// This is a <see cref="String.Format"/> pattern, where <c>{0}</c> /// is the number of minutes. /// </remarks> public string MinutesAgo { get; set; } public string OneHourAgo { get; set; } public string HoursAgo { get; set; } public string Yesterday { get; set; } public string DaysAgo { get; set; } public string LastMonth { get; set; } public string MonthsAgo { get; set; } public string LastYear { get; set; } public string YearsAgo { get; set; } /// <summary> Gets or sets the term for"ages ago". </summary> public string AgesAgo { get; set; } /// <summary> /// Gets or sets the threshold beyond which the fuzzy date should be /// considered"ages ago". /// </summary> public TimeSpan AgesAgoThreshold { get; set; } /// <summary> /// Initialises a new <see cref="Grammar"/> instance with the /// specified properties. /// </summary> private void Initialise(string justNow, string minutesAgo, string oneHourAgo, string hoursAgo, string yesterday, string daysAgo, string lastMonth, string monthsAgo, string lastYear, string yearsAgo, string agesAgo, TimeSpan agesAgoThreshold) { ... } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | public static class FuzzyDateExtensions { public static string ToFuzzyDateString(this TimeSpan timespan) { return timespan.ToFuzzyDateString(new Grammar()); } public static string ToFuzzyDateString(this TimeSpan timespan, Grammar grammar) { return GetFuzzyDateString(timespan, grammar); } public static string ToFuzzyDateString(this DateTime datetime) { return (DateTime.Now - datetime).ToFuzzyDateString(); } public static string ToFuzzyDateString(this DateTime datetime, Grammar grammar) { return (DateTime.Now - datetime).ToFuzzyDateString(grammar); } private static string GetFuzzyDateString(TimeSpan timespan, Grammar grammar) { timespan = timespan.Duration(); if (timespan >= grammar.AgesAgoThreshold) { return grammar.AgesAgo; } if (timespan < new TimeSpan(0, 2, 0)) // 2 minutes { return grammar.JustNow; } if (timespan < new TimeSpan(1, 0, 0)) // 1 hour { return String.Format(grammar.MinutesAgo, timespan.Minutes); } if (timespan < new TimeSpan(1, 55, 0)) // 1 hour 55 minutes { return grammar.OneHourAgo; } if (timespan < new TimeSpan(12, 0, 0) // 12 hours && (DateTime.Now - timespan).IsToday()) { return String.Format(grammar.HoursAgo, timespan.RoundedHours()); } if ((DateTime.Now.AddDays(1) - timespan).IsToday()) { return grammar.Yesterday; } if (timespan < new TimeSpan(32, 0, 0, 0) // 32 days && (DateTime.Now - timespan).IsThisMonth()) { return String.Format(grammar.DaysAgo, timespan.RoundedDays()); } if ((DateTime.Now.AddMonths(1) - timespan).IsThisMonth()) { return grammar.LastMonth; } if (timespan < new TimeSpan(365, 0, 0, 0, 0) // 365 days && (DateTime.Now - timespan).IsThisYear()) { return String.Format(grammar.MonthsAgo, timespan.RoundedMonths()); } if ((DateTime.Now - timespan).AddYears(1).IsThisYear()) { return grammar.LastYear; } return String.Format(grammar.YearsAgo, timespan.RoundedYears()); } } |
我想要达到的一个关键点是"今天"只意味着"这个日历日",所以
1 2 3 4 | public static bool IsToday(this DateTime date) { return date.DayOfYear == DateTime.Now.DayOfYear && date.IsThisYear(); } |
四舍五入的方法是这样的(我已经包括了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static int RoundedDays(this TimeSpan timespan) { return (timespan.Hours > 12) ? timespan.Days + 1 : timespan.Days; } public static int RoundedMonths(this TimeSpan timespan) { DateTime then = DateTime.Now - timespan; // Number of partial months elapsed since 1 Jan, AD 1 (DateTime.MinValue) int nowMonthYears = DateTime.Now.Year * 12 + DateTime.Now.Month; int thenMonthYears = then.Year * 12 + then.Month; return nowMonthYears - thenMonthYears; } |
我希望人们发现这个有用和/或有趣:o)
使用Fluent日期时间
1 2 3 4 5 6 | 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(); |
在PHP中,我这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <?php function timesince($original) { // array of time period chunks $chunks = array( array(60 * 60 * 24 * 365 , 'year'), array(60 * 60 * 24 * 30 , 'month'), array(60 * 60 * 24 * 7, 'week'), array(60 * 60 * 24 , 'day'), array(60 * 60 , 'hour'), array(60 , 'minute'), ); $today = time(); /* Current unix time */ $since = $today - $original; if($since > 604800) { $print = date("M jS", $original); if($since > 31536000) { $print .="," . date("Y", $original); } return $print; } // $j saves performing the count function each time around the loop for ($i = 0, $j = count($chunks); $i < $j; $i++) { $seconds = $chunks[$i][0]; $name = $chunks[$i][1]; // finding the biggest chunk (if the chunk fits, break) if (($count = floor($since / $seconds)) != 0) { break; } } $print = ($count == 1) ? '1 '.$name :"$count {$name}s"; return $print ." ago"; } ?> |
我想我可以用类和多态性来尝试一下。我以前的迭代使用了子类,结果开销太大。我已经切换到更灵活的委托/公共属性对象模型,这明显更好。我的代码稍微准确一点,我希望我能想出一个更好的方法来生成"几个月前"的代码,它看起来并没有设计得太多。
我想我还是会坚持Jeff的if-then cascade,因为它的代码更少,而且更简单(确保它按预期工作肯定更容易)。
对于下面的代码printRelativeTime.getRelativeTimeMessage(TimeSpan Ago)返回相对时间消息(例如"昨天")。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 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); } } |
当你知道观看者的时区时,以天为单位使用日历日可能会更清晰。我不熟悉.NET库,所以我不知道您在C中是如何做到这一点的,不幸的是。
在消费类网站上,你也可以在一分钟内手摇成波浪形。"不到一分钟前"或刚刚"就足够了。
你可以试试这个。我想它会正常工作的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | long delta = new Date().getTime() - date.getTime(); const int SECOND = 1; const int MINUTE = 60 * SECOND; const int HOUR = 60 * MINUTE; const int DAY = 24 * HOUR; const int MONTH = 30 * DAY; if (delta < 0L) { return"not yet"; } if (delta < 1L * MINUTE) { return ts.Seconds == 1 ?"one second ago" : ts.Seconds +" seconds ago"; } if (delta < 2L * MINUTE) { return"a minute ago"; } if (delta < 45L * MINUTE) { return ts.Minutes +" minutes ago"; } if (delta < 90L * MINUTE) { return"an hour ago"; } if (delta < 24L * HOUR) { return ts.Hours +" hours ago"; } if (delta < 48L * HOUR) { return"yesterday"; } if (delta < 30L * DAY) { return ts.Days +" days ago"; } if (delta < 12L * MONTH) { int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); return months <= 1 ?"one month ago" : months +" months ago"; } else { int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); return years <= 1 ?"one year ago" : years +" years ago"; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | using System; using System.Collections.Generic; using System.Linq; public static class RelativeDateHelper { private static Dictionary<double, Func<double, string>> sm_Dict = null; private static Dictionary<double, Func<double, string>> DictionarySetup() { var dict = new Dictionary<double, Func<double, string>>(); dict.Add(0.75, (mins) =>"less than a minute"); dict.Add(1.5, (mins) =>"about a minute"); dict.Add(45, (mins) => string.Format("{0} minutes", Math.Round(mins))); dict.Add(90, (mins) =>"about an hour"); dict.Add(1440, (mins) => string.Format("about {0} hours", Math.Round(Math.Abs(mins / 60)))); // 60 * 24 dict.Add(2880, (mins) =>"a day"); // 60 * 48 dict.Add(43200, (mins) => string.Format("{0} days", Math.Floor(Math.Abs(mins / 1440)))); // 60 * 24 * 30 dict.Add(86400, (mins) =>"about a month"); // 60 * 24 * 60 dict.Add(525600, (mins) => string.Format("{0} months", Math.Floor(Math.Abs(mins / 43200)))); // 60 * 24 * 365 dict.Add(1051200, (mins) =>"about a year"); // 60 * 24 * 365 * 2 dict.Add(double.MaxValue, (mins) => string.Format("{0} years", Math.Floor(Math.Abs(mins / 525600)))); return dict; } public static string ToRelativeDate(this DateTime input) { TimeSpan oSpan = DateTime.Now.Subtract(input); double TotalMinutes = oSpan.TotalMinutes; string Suffix =" ago"; if (TotalMinutes < 0.0) { TotalMinutes = Math.Abs(TotalMinutes); Suffix =" from now"; } if (null == sm_Dict) sm_Dict = DictionarySetup(); return sm_Dict.First(n => TotalMinutes < n.Key).Value.Invoke(TotalMinutes) + Suffix; } } |
与此问题的另一个答案相同,但作为带有静态字典的扩展方法。
@杰夫
1
对
所以你可以这么做
1 | (DateTime.UtcNow - dt).TotalSeconds |
我还惊讶地看到常量手工相乘,然后在注释中添加了乘法。那是不是有些错误的优化?
用于客户端GWT使用的Java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import java.util.Date; public class RelativeDateFormat { private static final long ONE_MINUTE = 60000L; private static final long ONE_HOUR = 3600000L; private static final long ONE_DAY = 86400000L; private static final long ONE_WEEK = 604800000L; public static String format(Date date) { long delta = new Date().getTime() - date.getTime(); if (delta < 1L * ONE_MINUTE) { return toSeconds(delta) == 1 ?"one second ago" : toSeconds(delta) +" seconds ago"; } if (delta < 2L * ONE_MINUTE) { return"one minute ago"; } if (delta < 45L * ONE_MINUTE) { return toMinutes(delta) +" minutes ago"; } if (delta < 90L * ONE_MINUTE) { return"one hour ago"; } if (delta < 24L * ONE_HOUR) { return toHours(delta) +" hours ago"; } if (delta < 48L * ONE_HOUR) { return"yesterday"; } if (delta < 30L * ONE_DAY) { return toDays(delta) +" days ago"; } if (delta < 12L * 4L * ONE_WEEK) { long months = toMonths(delta); return months <= 1 ?"one month ago" : months +" months ago"; } else { long years = toYears(delta); return years <= 1 ?"one year ago" : years +" years ago"; } } private static long toSeconds(long date) { return date / 1000L; } private static long toMinutes(long date) { return toSeconds(date) / 60L; } private static long toHours(long date) { return toMinutes(date) / 60L; } private static long toDays(long date) { return toHours(date) / 24L; } private static long toMonths(long date) { return toDays(date) / 30L; } private static long toYears(long date) { return toMonths(date) / 365L; } } |
您可以使用TimeAgo扩展名,其外观如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public static string TimeAgo(this DateTime dateTime) { string result = string.Empty; var timeSpan = DateTime.Now.Subtract(dateTime); if (timeSpan <= TimeSpan.FromSeconds(60)) { result = string.Format("{0} seconds ago", timeSpan.Seconds); } else if (timeSpan <= TimeSpan.FromMinutes(60)) { result = timeSpan.Minutes > 1 ? String.Format("about {0} minutes ago", timeSpan.Minutes) : "about a minute ago"; } else if (timeSpan <= TimeSpan.FromHours(24)) { result = timeSpan.Hours > 1 ? String.Format("about {0} hours ago", timeSpan.Hours) : "about an hour ago"; } else if (timeSpan <= TimeSpan.FromDays(30)) { result = timeSpan.Days > 1 ? String.Format("about {0} days ago", timeSpan.Days) : "yesterday"; } else if (timeSpan <= TimeSpan.FromDays(365)) { result = timeSpan.Days > 30 ? String.Format("about {0} months ago", timeSpan.Days / 30) : "about a month ago"; } else { result = timeSpan.Days > 365 ? String.Format("about {0} years ago", timeSpan.Days / 365) : "about a year ago"; } return result; } |
或者使用jquery插件和来自timeago的Razor扩展。
您可以通过执行这个逻辑客户端来减少服务器端负载。查看一些digg页面上的源代码以供参考。它们让服务器发出一个由javascript处理的epoch时间值。这样就不需要管理最终用户的时区。新的服务器端代码如下:
1 2 3 4 | public string GetRelativeTime(DateTime timeStamp) { return string.Format("printdate({0});", timeStamp.ToFileTimeUtc()); } |
甚至可以在那里添加noscript块并执行toString()。
下面是StackOverflow使用的算法,但使用错误修复(不是"一小时前")在Perlish伪代码中更简洁地重写。函数在几秒钟前(正数)返回一个对人友好的字符串,如"3小时前"或"昨天"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | agoify($delta) local($y, $mo, $d, $h, $m, $s); $s = floor($delta); if($s<=1) return"a second ago"; if($s<60) return"$s seconds ago"; $m = floor($s/60); if($m==1) return"a minute ago"; if($m<45) return"$m minutes ago"; $h = floor($m/60); if($h==1) return"an hour ago"; if($h<24) return"$h hours ago"; $d = floor($h/24); if($d<2) return"yesterday"; if($d<30) return"$d days ago"; $mo = floor($d/30); if($mo<=1) return"a month ago"; $y = floor($mo/12); if($y<1) return"$mo months ago"; if($y==1) return"a year ago"; return"$y years ago"; |
这是我从比尔·盖茨的博客上得到的。我需要在我的浏览器历史上找到它,我会给你链接。
要执行相同操作的javascript代码(按要求):
1 2 3 4 5 6 7 8 9 10 11 | function posted(t) { var now = new Date(); var diff = parseInt((now.getTime() - Date.parse(t)) / 1000); if (diff < 60) { return 'less than a minute ago'; } else if (diff < 120) { return 'about a minute ago'; } else if (diff < (2700)) { return (parseInt(diff / 60)).toString() + ' minutes ago'; } else if (diff < (5400)) { return 'about an hour ago'; } else if (diff < (86400)) { return 'about ' + (parseInt(diff / 3600)).toString() + ' hours ago'; } else if (diff < (172800)) { return '1 day ago'; } else {return (parseInt(diff / 86400)).toString() + ' days ago'; } } |
基本上,你是以秒为单位工作的…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /** * {@code date1} has to be earlier than {@code date2}. */ public static String relativize(Date date1, Date date2) { assert date2.getTime() >= date1.getTime(); long duration = date2.getTime() - date1.getTime(); long converted; if ((converted = TimeUnit.MILLISECONDS.toDays(duration)) > 0) { return String.format("%d %s ago", converted, converted == 1 ?"day" :"days"); } else if ((converted = TimeUnit.MILLISECONDS.toHours(duration)) > 0) { return String.format("%d %s ago", converted, converted == 1 ?"hour" :"hours"); } else if ((converted = TimeUnit.MILLISECONDS.toMinutes(duration)) > 0) { return String.format("%d %s ago", converted, converted == 1 ?"minute" :"minutes"); } else if ((converted = TimeUnit.MILLISECONDS.toSeconds(duration)) > 0) { return String.format("%d %s ago", converted, converted == 1 ?"second" :"seconds"); } else { return"just now"; } } |
如果您想要像
1 | TimeSpan timeDiff = DateTime.Now-CreatedDate; |
然后您可以访问您喜欢的值:
1 2 | timeDiff.Days timeDiff.Hours |
等。。。
我想已经有很多关于这篇文章的答案了,但是我们可以使用这个,它很容易使用,就像插件一样,也很容易被程序员阅读。发送您的特定日期,并以字符串形式获取其值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public string RelativeDateTimeCount(DateTime inputDateTime) { string outputDateTime = string.Empty; TimeSpan ts = DateTime.Now - inputDateTime; if (ts.Days > 7) { outputDateTime = inputDateTime.ToString("MMMM d, yyyy"); } else if (ts.Days > 0) { outputDateTime = ts.Days == 1 ? ("about 1 Day ago") : ("about" + ts.Days.ToString() +" Days ago"); } else if (ts.Hours > 0) { outputDateTime = ts.Hours == 1 ? ("an hour ago") : (ts.Hours.ToString() +" hours ago"); } else if (ts.Minutes > 0) { outputDateTime = ts.Minutes == 1 ? ("1 minute ago") : (ts.Minutes.ToString() +" minutes ago"); } else outputDateTime ="few seconds ago"; return outputDateTime; } |
1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public string getRelativeDateTime(DateTime date) { TimeSpan ts = DateTime.Now - date; if (ts.TotalMinutes < 1)//seconds ago return"just now"; if (ts.TotalHours < 1)//min ago return (int)ts.TotalMinutes == 1 ?"1 Minute ago" : (int)ts.TotalMinutes +" Minutes ago"; if (ts.TotalDays < 1)//hours ago return (int)ts.TotalHours == 1 ?"1 Hour ago" : (int)ts.TotalHours +" Hours ago"; if (ts.TotalDays < 7)//days ago return (int)ts.TotalDays == 1 ?"1 Day ago" : (int)ts.TotalDays +" Days ago"; if (ts.TotalDays < 30.4368)//weeks ago return (int)(ts.TotalDays / 7) == 1 ?"1 Week ago" : (int)(ts.TotalDays / 7) +" Weeks ago"; if (ts.TotalDays < 365.242)//months ago return (int)(ts.TotalDays / 30.4368) == 1 ?"1 Month ago" : (int)(ts.TotalDays / 30.4368) +" Months ago"; //years ago return (int)(ts.TotalDays / 365.242) == 1 ?"1 Year ago" : (int)(ts.TotalDays / 365.242) +" Years ago"; } |
一个月和一年中的天数转换值取自谷歌。
我将为此提供一些方便的扩展方法,并使代码更具可读性。首先,为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public static class TimeSpanExtensions { public static TimeSpan Days(this int value) { return new TimeSpan(value, 0, 0, 0); } public static TimeSpan Hours(this int value) { return new TimeSpan(0, value, 0, 0); } public static TimeSpan Minutes(this int value) { return new TimeSpan(0, 0, value, 0); } public static TimeSpan Seconds(this int value) { return new TimeSpan(0, 0, 0, value); } public static TimeSpan Milliseconds(this int value) { return new TimeSpan(0, 0, 0, 0, value); } public static DateTime Ago(this TimeSpan value) { return DateTime.Now - value; } } |
然后,一个给
1 2 3 4 5 6 7 | public static class DateTimeExtensions { public static DateTime Ago(this DateTime dateTime, TimeSpan delta) { return dateTime - delta; } } |
现在,您可以执行如下操作:
1 2 3 4 | var date = DateTime.Now; date.Ago(2.Days()); // 2 days ago date.Ago(7.Hours()); // 7 hours ago date.Ago(567.Milliseconds()); // 567 milliseconds ago |
当然,解决"1小时前"问题的一个简单方法是增加"1小时前"的有效窗口。变化
1 2 3 4 | if (delta < 5400) // 90 * 60 { return"an hour ago"; } |
进入之内
1 2 3 4 | if (delta < 7200) // 120 * 60 { return"an hour ago"; } |
这意味着110分钟前发生的事情将被解读为"一小时前"——这可能并不完美,但我认为这比"1小时前"的现状要好。
这是我的职责,就像一个魅力:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public static string RelativeDate(DateTime theDate) { var span = DateTime.Now - theDate; if (span.Days > 365) { var years = (span.Days / 365); if (span.Days % 365 != 0) years += 1; return $"about {years} {(years == 1 ?"year" :"years")} ago"; } if (span.Days > 30) { var months = (span.Days / 30); if (span.Days % 31 != 0) months += 1; return $"about {months} {(months == 1 ?"month" :"months")} ago"; } if (span.Days > 0) return $"about {span.Days} {(span.Days == 1 ?"day" :"days")} ago"; if (span.Hours > 0) return $"about {span.Hours} {(span.Hours == 1 ?"hour" :"hours")} ago"; if (span.Minutes > 0) return $"about {span.Minutes} {(span.Minutes == 1 ?"minute" :"minutes")} ago"; if (span.Seconds > 5) return $"about {span.Seconds} seconds ago"; return span.Seconds <= 5 ?"about 5 seconds ago" : string.Empty; } |
文森特答案的土耳其语本地化版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | const int SECOND = 1; const int MINUTE = 60 * SECOND; const int HOUR = 60 * MINUTE; const int DAY = 24 * HOUR; const int MONTH = 30 * DAY; var ts = new TimeSpan(DateTime.UtcNow.Ticks - yourDate.Ticks); double delta = Math.Abs(ts.TotalSeconds); if (delta < 1 * MINUTE) return ts.Seconds +" saniye ?nce"; if (delta < 45 * MINUTE) return ts.Minutes +" dakika ?nce"; if (delta < 24 * HOUR) return ts.Hours +" saat ?nce"; if (delta < 48 * HOUR) return"dün"; if (delta < 30 * DAY) return ts.Days +" gün ?nce"; if (delta < 12 * MONTH) { int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); return months +" ay ?nce"; } else { int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); return years +" y?l ?nce"; } |
我的方法要简单得多。您可以根据需要调整返回字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static string TimeLeft(DateTime utcDate) { TimeSpan timeLeft = DateTime.UtcNow - utcDate; string timeLeftString =""; if (timeLeft.Days > 0) { timeLeftString += timeLeft.Days == 1 ? timeLeft.Days +" day" : timeLeft.Days +" days"; } else if (timeLeft.Hours > 0) { timeLeftString += timeLeft.Hours == 1 ? timeLeft.Hours +" hour" : timeLeft.Hours +" hours"; } else { timeLeftString += timeLeft.Minutes == 1 ? timeLeft.Minutes+" minute" : timeLeft.Minutes +" minutes"; } return timeLeftString; } |