1386

주어진 특정DateTime값, 상대 시간을 어떻게 표시합니까?

  • 2 시간 전
  • 3 일 전
  • 한 달 전


  • 상대적인 시간을 미래부터 미래로 계산하고 싶다면 어떻게해야할까요? - Jhonny D. Cano -Leftware-
  • moment.js는 아주 좋은 데이트 파싱 라이브러리입니다. 필요에 따라 그 (서버 측 또는 클라이언트 측)를 사용할 수 있습니다. 아무도 그것을 여기에서 언급하지 않았기 때문에 단지 fyi - code ninja
  • .net 패키지가 있습니다.github.com/NickStrupat/TimeAgo어느 것이 꽤 많이 묻는 지 않습니다. - Rossco

30 답변


909

제프,당신의 코드멋지지만 상수로 더 명확해질 수 있습니다 (코드 완료에서 제안됨).

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


  • 나는 그러한 상수를 열정으로 싫어한다. 누구에게도 이것이 잘못된 것처럼 보입니까?Thread.Sleep(1 * MINUTE)? 1000 배만큼 잘못 되었기 때문에. - Roman Starkov
  • const int SECOND = 1;이렇게 이상한 순간은 1 초입니다. - seriousdev
  • 이러한 유형의 코드는 현지화가 거의 불가능합니다. 앱이 영어로만 남아 있다면 괜찮습니다. 그러나 다른 언어로 점프하면이 같은 논리를하는 것을 싫어할 것입니다. 모두들 ... - Nik Reiman
  • 정수가 정확하게 그 값을 설명하기 위해 이름이 변경되면 이해하기가 더 쉽다고 생각합니다. 그래서 SecondsPerMinute = 60; MinutesPerHour = 60; SecondsPerHour = MinutesPerHour * SecondsPerHour; MINUTE = 60이라고 부르는 것만으로는 독자가 그 값이 무엇인지 결정할 수 없습니다. - slolife
  • 왜 조 (Joe 제외)가 잘못된 & # 39; Yesterday & # 39; 또는 & # 39 일 전 & # 39; 가치 ??? 어제는 시간 계산이 아니라 일일 계산입니다. 그래서 네, 적어도 두 번의 빈번한 경우에 이것은 잘못된 코드입니다. - CtrlX

353

jquery.timeago 플러그인

Stack Overflow는 jQuery를 광범위하게 사용하기 때문에 Jeff는jquery.timeago 플러그인.

은혜:

  • 페이지가 10 분 전에 열렸음에도 불구하고 "1 분 전에"타임 스탬프를 피하십시오. 자동으로 시간을 새로 고칩니다.
  • 타임 스탬프가 서버에서 계산되지 않기 때문에 웹 응용 프로그램에서 페이지 및 / 또는 조각 캐싱을 최대한 활용할 수 있습니다.
  • 멋진 아이처럼 마이크로 포맷을 사용하게됩니다.

DOM 준비에 타임 스탬프에 첨부하십시오.

jQuery(document).ready(function() {
    jQuery('abbr.timeago').timeago();
});

이것은 모든abbrtimeago 클래스와ISO 8601제목의 타임 스탬프 :

<abbr class="timeago" title="2008-07-17T09:24:17Z">July 17, 2008</abbr>

이런 식으로 :

<abbr class="timeago" title="July 17, 2008">4 months ago</abbr>

4 개월 전. 시간이 지남에 따라 타임 스탬프가 자동으로 업데이트됩니다.

면책 조항 : 나는이 플러그인을 썼다. 그래서 나는 편견을 갖고있다.


  • Seb, Javascript가 비활성화 된 경우 원래 abbr 태그 사이에 넣은 문자열이 표시됩니다. 일반적으로 이것은 원하는 형식의 날짜 또는 시간 일뿐입니다. Timeago는 정상적으로 저하됩니다. 훨씬 간단 해지지는 않습니다. - Ryan McGeary
  • Ryan, 나는 그렇게 오래 전에 시간을 사용하라고 제안했다. 제프의 반응이 울부 짖었습니다. 저는 여러분이 앉아 있다고 제안합니다.stackoverflow.uservoice.com/pages/1722-general/suggestions/… - Rob Fonseca-Ensor
  • 고, 고마워. 그건 괜찮아. 특히 SO 페이지에 많은 타임 스탬프가 있지만 전환하는 동안 하나의 번호 만 바뀌면 거의 눈에 띄지 않습니다. 비록 그가 자동 업데이트를 피하기로 선택했다 할지라도 그는 페이지 캐싱의 이점을 적어도 인식했을 것이라고 생각했을 것입니다. Jeff가 플러그인을 개선하기 위해 피드백을 제공 할 수 있었는지 확신 할 수 있습니다. 나는 위안을 알고있는 사이트를 좋아한다.arstechnica.com그걸 써. - Ryan McGeary
  • @ Rob Fonseca-Ensor - 이제 나도 울부 짖습니다. 정확한 정보를 보여주기 위해 분당 한 번 업데이트하는 방법,어떠한 방식으로1 초에 한 번 깜박이는 텍스트 관련? - Daniel Earwicker
  • 질문은 C #에 관한 것입니다. jQuery 플러그인이 어떻게 관련되는지 보지 못했습니다. - BartoszKP

324

방법은 다음과 같습니다.

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

제안? 코멘트? 이 알고리즘을 개선하는 방법은?


  • "& lt; 48 * 60 * 60s " & quot; 어제 & quot;에 대한 다소 독창적 인 정의입니다. 수요일 오전 9시에 월요일에 오전 9시 1 분을 & quot; 어제 & quot;라고 생각하십니까? 어제 또는 & quot; n 일 전 & quot;에 대한 알고리즘을 생각해 보았습니다. 자정 전후에 고려해야합니다. - Joe
  • 컴파일러는 일반적으로 24 * 60 * 60과 같은 상수 표현식을 사전 계산할 때 꽤 유용합니다. 따라서 직접 계산하지 않고 직접 계산하여 86400이되고 주석에 원래 표현식을 넣을 수 있습니다 - zvolkov
  • 이 함수가 주를 제외한다는 것을 알았습니다. - jray
  • @ bzlm 내가 일하고있는 프로젝트에서 내가 한 것 같아. 여기에서의 동기는 다른 사람들에게이 코드 샘플에서 몇 주를 생략하라고 경고하는 것이 었습니다. 그것을하는 방법에 관해서는, 그것은 나에게 꽤 솔직하게 보였다. - jray
  • 알고리즘을 개선하는 좋은 방법은 "2 개월 21 일 전", "1 시간 40 분 전"과 같은 2 단위를 표시하는 것입니다. 정확성을 높이기 위해 - Evgeny Levin

87

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

나는 그 간결함과 새로운 틱 포인트를 추가 할 수있는 능력 때문에이 버전을 선호한다. 이것은 a로 캡슐화 될 수 있었다Latest()긴 1 라이너 대신 타임스펀으로 연장해야하지만 게시의 간결함을 위해 이는 가능합니다.1 시간 전에 2 시간이 경과 할 때까지 시간을 제공하여 1 시간 전을 수정합니다.


  • 이 함수를 사용하여 여러 가지 문제가 발생합니다. 예를 들어 theDate = DateTime.Now.AddMinutes (-40); & # 39; 40 시간 전 & # 39;을 보았지만 마이클의 리팩토 모드 응답으로는 & # 39; 40 분 전에 & # 39; ? - GONeale
  • 나는 당신이 0을 놓치고 있다고 생각한다 : long = = (DateTime.Now.Ticks - theDate.Ticks) / 10000000; - robnardo
  • 흠,이 코드는 작동하지만 사전에있는 키의 순서가 특정 순서로 있다고 가정하는 것은 올바르지 않으며 무효합니다. Dictionary는 Long이지만 int!를 반환하지 않는 Object.GetHashCode ()를 사용합니다. 이들을 정렬하려면 SortedList & lt; long, string & gt;을 사용해야합니다. if / else의 집합에서 평가되는 임계 값에 어떤 문제가 있습니까? / else / if? else? 당신은 같은 수의 비교를 얻습니다. 참고로 long.MaxValue의 해시는 int.MinValue와 같습니다. - CodeMonkeyKing
  • OP 분실 됨. 일 & gt; 30? t.Days / 30 : - Lars Holm Jensen
  • @CodeMonkeyKing에서 언급 한 문제를 해결하려면SortedDictionary평야 대신에Dictionary: 사용법은 동일하지만 키가 정렬되도록합니다. 그러나 그때에도 알고리즘에는 결함이 있습니다.RelativeDate(DateTime.Now.AddMonths(-3).AddDays(-3))보고"95 개월 전"어떤 사전 유형을 사용하든 관계없이 사용하지 않는 문안 (3 개월 전 또는 4 개월 전)을 반환합니다. 지난 해에 날짜를 만드십시오. (나는 이것을 12 월에 테스트 했으므로이 경우 발생하지 않아야합니다.) - Matt

69

여기 PHP를위한 Jeffs Script의 재 작성 :

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


  • 질문은 ~이야C # 태그PHP 코드? - Kiquenet

63

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 버전 :

static readonly SortedList<double, Func<TimeSpan, string>> offsets = 
   new SortedList<double, Func<TimeSpan, string>>
{
    { 0.75, _ => "less than a minute"},
    { 1.5, _ => "about a minute"},
    { 45, x => $"{x.TotalMinutes:F0} minutes"},
    { 90, x => "about an hour"},
    { 1440, x => $"about {x.TotalHours:F0} hours"},
    { 2880, x => "a day"},
    { 43200, x => $"{x.TotalDays:F0} days"},
    { 86400, x => "about a month"},
    { 525600, x => $"{x.TotalDays / 30:F0} months"},
    { 1051200, x => "about a year"},
    { double.MaxValue, x => $"{x.TotalDays / 365:F0} years"}
};

public static string ToRelativeDate(this DateTime input)
{
    TimeSpan x = DateTime.Now - input;
    string Suffix = x.TotalMinutes > 0 ? " ago" : " from now";
    x = new TimeSpan(Math.Abs(x.Ticks));
    return offsets.First(n => x.TotalMinutes < n.Key).Value(x) + Suffix;
}



49

다음은 미래 및 과거 날짜를 처리하는 DateTime 클래스의 확장 메서드로 추가 한 구현이며 찾고있는 세부 수준을 지정할 수있는 근사 옵션을 제공합니다 ( "3 시간 전"vs "3 시간, 23 분, 12 초 전) ") :

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


39

클라이언트 측에서도 이것을 계산하는 것이 좋습니다. 서버 작업이 줄어 듭니다.

다음은 내가 사용하는 버전입니다 (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);
                });
        };
}


  • 질문은 ~이야C # 태그자바 스크립트 코드? - Kiquenet

30

@jeff

IMHO 네가 좀 길어 보인다. 그러나 "어제"와 "년"에 대한 지원이 조금 더 강건 해 보입니다. 그러나이 경험을 사용했을 때 처음 30 일 동안 콘텐츠를 볼 가능성이 가장 큽니다. 그 후에 오는 것은 정말로 하드 코어 사람들입니다. 그래서 저는 제가 이것을 보통 짧고 단순하게 유지하기로 선택하는 이유입니다.

이것은 현재 내 웹 사이트 중 하나에서 사용하고있는 방법입니다. 상대 날짜, 시간, 시간 만 반환합니다. 그리고 사용자는 출력에서 "이전"을 때 리야합니다.

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


30

또한 Nuget에 Humanizer라고 불리는 패키지가 있는데 실제로 잘 작동합니다.

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"

Scott Hanselman이 그것에 대한 글을 남겼습니다.블로그


  • friendly note : .net 4.5 이상에서 Humanizer를 설치하지 마십시오. Humanizer.Core 부분 만 설치하십시오. 다른 언어 패키지가이 버전에서 지원되지 않습니다. - Ahmad
  • 매우 유용합니다! 이 답변은이 목록에서 훨씬 더 높아야합니다. 제가 100 표를 얻었다면 이것을드립니다. 외관상으로는 (JS 땅에서 오는),이 포장을 찾는 것은 쉽지 않았다. - kumar_harsh

23

파티에 늦은 지 2 년이되었지만, 과거와 미래의 날짜 모두에 대해이 작업을 수행해야한다는 요구가 있었기 때문에제프'모래빈센트이것에. 그것은 ternarytastic 광상입니다! :)

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


22

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


  • 질문은 ~이야C # 태그Java 코드? - Kiquenet

21

iPhone Objective-C 버전

+ (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];
    }
}


19

PHP에서는 다음과 같이합니다.

<?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";

} ?>


  • 질문은 ~이야C # 태그. 왜 이거지?PHP 코드?IMHO, C # 코드 만 적용 - Kiquenet

19

세상과 남편이 코드 샘플을 게시하는 것으로 보이는 것을 감안할 때,이 답변 몇 개를 토대로 잠시 전에 쓴 것입니다.

이 코드를 지역화 할 수있는 구체적인 필요성이있었습니다. 그래서 두 가지 수업이 있습니다.Grammar지역화 할 수있는 용어를 지정하는FuzzyDateExtensions확장 메서드를 많이 보유하고 있습니다. 미래의 datetimes를 처리 할 필요가 없었으므로이 코드로 처리 할 시도는 없습니다.

소스에 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();
}

반올림 방법은 다음과 같습니다 (I 've includedRoundedMonths, 그것은 조금 다릅니다) :

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)


18

~을 사용하여유창한 날짜 시간

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();


15

나는 클래스와 다형성을 사용하여 이것을 줄 것이라고 생각했다. 나는 너무 많은 오버 헤드를 가지게 된 하위 분류를 사용하는 이전 반복을 가졌습니다. 상당히 유연한 대리자 / 공개 속성 객체 모델로 전환했습니다. 내 코드가 좀 더 정확하다. 너무 지나치게 설계되지 않은 "개월 전"을 생성하는 더 좋은 방법을 찾았 으면 좋겠다.

나는 코드가 적기 때문에 제프의 if-then 캐스케이드를 계속 고수 할 것이라고 생각한다. 더 간단하다. (기대했던대로 작동하는 것이 확실하다.)

아래의 코드는PrintRelativeTime.GetRelativeTimeMessage (TimeSpan 전)상대 시간 메시지를 반환합니다 (예 : '어제').

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


12

시청자의 시간대를 알면 일별로 캘린더 날짜를 사용하는 것이 더 명확 할 수 있습니다. 저는 .NET 라이브러리에 익숙하지 않아 불행히도 C #에서 그렇게 할 수 있는지 알지 못합니다.

소비자 사이트에서 1 분 안에 손을 씻을 수도 있습니다. "1 분 미만"또는 "지금 당장"은 충분히 좋을 수 있습니다.


12

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

같은이 질문에 대한 또 다른 대답정적 사전을 사용한 확장 방법으로 사용됩니다.


  • 사전이 너를 여기서 샀어? - StriplingWarrior
  • StriplingWarrior : switch 문이나 if / else 문 스택과 비교하여 읽기 및 수정이 쉽습니다. 딕셔너리는 정적 인 것을 의미하고, Func & lt;, & gt; ToRelativeDate를 사용할 때마다 개체를 만들어야합니다. 내 답변에 링크 된 것과 비교하여 한 번만 생성되었습니다. - Chris Charabaruk
  • 내가 참조. 나는 생각하고 있었다.Dictionary"항목이 반환되는 순서는 정의되지 않았습니다." (msdn.microsoft.com/en-us/library/xfhwa508.aspx) 아마도 순서대로 머물러있게하는 것만큼 조회 시간을 신경 쓰지 않을 때 사용할 최상의 데이터 구조가 아닐 것입니다. - StriplingWarrior
  • StriplingWarrior : 저는 LINQ가 이것을 사용할 때 고려해야한다고 생각합니다.Dictionary에스. 그래도 불편하다면 다음을 사용할 수 있습니다.SortedDictionary, 그러나 나의 자신의 경험은 불필요한 것을 보여준다. - Chris Charabaruk

12

너는 이것을 시도 할 수있다. 나는 그것이 올바르게 작동 할 것이라고 생각한다.

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


10

@ 제프

var ts = new TimeSpan(DateTime.UtcNow.Ticks - dt.Ticks);

에 대해 뺄셈하기DateTime~을 반환합니다.TimeSpan어쨌든.

그럼 당신은 할 수 있어요.

(DateTime.UtcNow - dt).TotalSeconds

저는 또한 손으로 곱해진 상수와 곱셈을 추가 한 주석을 보게되어 놀랍습니다. 잘못된 판단 이었습니까?


9

클라이언트 측 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;
 }

}


  • 질문은 ~이야C # 태그. 왜 이거지?Java 코드?IMHO, C # 코드 만 적용 - Kiquenet

9

이 논리를 클라이언트 측에서 수행하여 서버 측로드를 줄일 수 있습니다. 참조를 위해 일부 Digg 페이지에서 소스를보십시오. 그들은 서버가 자바 스크립트에 의해 처리되는 획기적인 시간 값을 방출하도록합니다. 이렇게하면 최종 사용자의 시간대를 관리 할 필요가 없습니다. 새로운 서버 측 코드는 다음과 같습니다.

public string GetRelativeTime(DateTime timeStamp)
{
    return string.Format("<script>printdate({0});</script>", timeStamp.ToFileTimeUtc());
}

거기에 NOSCRIPT 블록을 추가하고 ToString ()을 수행 할 수도 있습니다.


8

다음은 stackoverflow가 사용하지만 버그 수정을 사용하여 perlish 의사 코드에서보다 간결하게 다시 작성된 알고리즘입니다 ( "1 시간 전"없음). 이 함수는 몇 초 전에 (양의) 숫자를 취해 "3 시간 전"이나 "어제"와 같은 인간 친화적 인 문자열을 반환합니다.

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


8

당신이 사용할 수있는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;
}

또는 사용jQuery 플러그인Timeago의 Razor 확장 기능.


8

이것은 빌 게이츠 (Bill Gates)의 블로그에서 얻은 것입니다. 내 브라우저 기록에서 그것을 찾아야하고 나는 당신에게 링크를 줄 것이다.

동일한 작업을 수행하는 자바 스크립트 코드 (요청한대로) :

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

기본적으로, 당신은 초 단위로 일합니다 ...


6

/** 
 * {@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";
    }
}


6

이 게시물과 관련하여 이미 많은 답변이 있다고 생각하지만 플러그인처럼 사용하기 쉽고 프로그래머에게도 쉽게 읽을 수있는이 도구를 사용할 수 있습니다. 특정 날짜를 보내고 문자열 형식으로 값을 가져옵니다.

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


5

var ts = new TimeSpan(DateTime.Now.Ticks - dt.Ticks);


6

다음과 같은 출력을 원한다면"2 days, 4 hours and 12 minutes ago", 당신은 timespan 필요 :

TimeSpan timeDiff = DateTime.Now-CreatedDate;

그런 다음 원하는 값에 액세스 할 수 있습니다.

timeDiff.Days
timeDiff.Hours

기타...

연결된 질문


관련된 질문

최근 질문