给定特定的DateTime值,如何显示相对时间,例如:
2小时前3天前一个月前
给定特定的DateTime值,如何显示相对时间,例如:
2小时前3天前一个月前
当前回答
鉴于全世界和她的丈夫似乎都在发布代码样本,这是我不久前根据这些答案写的。
我特别需要这个代码可以本地化。所以我有两个类——Grammar,它指定了可本地化的术语,FuzzyDateExtensions,它包含一系列扩展方法。我不需要处理未来的日期时间,因此不尝试使用此代码处理它们。
为了简洁起见,我在源代码中保留了一些XMLdoc,但删除了大部分(显而易见的地方)。我也没有把每个班级成员都包括在这里:
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)
{ ... }
}
FuzzyDateString类包含:
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());
}
}
我想实现的一件关键事情,以及本地化,就是“今天”只意味着“这个日历日”,所以IsToday、IsThisMonth和IsThisYear方法如下:
public static bool IsToday(this DateTime date)
{
return date.DayOfYear == DateTime.Now.DayOfYear && date.IsThisYear();
}
舍入方法如下(我已包括RoundedMonths,因为这有点不同):
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)
其他回答
我认为已经有很多关于这篇文章的答案了,但你可以使用它,它就像插件一样容易使用,程序员也很容易阅读。发送您的特定日期,并以字符串形式获取其值:
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;
}
我也建议在客户端进行计算。服务器工作更少。
以下是我使用的版本(来自Zach Leatherman)
/*
* 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);
});
};
}
如果您想获得类似“2天4小时12分钟前”的输出,则需要一个时间跨度:
TimeSpan timeDiff = DateTime.Now-CreatedDate;
然后您可以访问您喜欢的值:
timeDiff.Days
timeDiff.Hours
等
@杰夫
var ts=新时间跨度(DateTime.UtcNow.Ticks-dt.Ticks);
对DateTime执行减法仍会返回TimeSpan。
所以你可以这样做
(DateTime.UtcNow - dt).TotalSeconds
我也很惊讶地看到常数用手相乘,然后注释加上乘法。这是错误的优化吗?
在Java中有没有一种简单的方法可以做到这一点?java.util.Date类似乎相当有限。
下面是我的快速而肮脏的Java解决方案:
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;
}