给定特定的DateTime值,如何显示相对时间,例如:

2小时前3天前一个月前


当前回答

当然,解决“1小时前”问题的一个简单方法是增加“一小时前”有效的窗口。改变

if (delta < 5400) // 90 * 60
{
    return "an hour ago";
}

into

if (delta < 7200) // 120 * 60
{
    return "an hour ago";
}

这意味着110分钟前发生的事情将被解读为“一小时前”——这可能并不完美,但我认为这比“1小时前”的现状要好。

其他回答

@杰夫

我知道你的有点长。然而,随着对“昨天”和“几年”的支持,它似乎确实更为有力。但根据我的经验,当使用此选项时,用户最有可能在前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();
}

@杰夫

var ts=新时间跨度(DateTime.UtcNow.Ticks-dt.Ticks);

对DateTime执行减法仍会返回TimeSpan。

所以你可以这样做

(DateTime.UtcNow - dt).TotalSeconds

我也很惊讶地看到常数用手相乘,然后注释加上乘法。这是错误的优化吗?

您可以使用TimeAgo扩展,如下所示:

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

或者使用带有Timeago的Razor扩展的jQuery插件。

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

用于客户端gwt的Java:

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

}