Vă mulțumim pentru susținere

Calculați timpul relativ în C #

Având o anumită valoare DateTime , cum pot afișa timpul relativ, cum ar fi:

  • Acum 2 ore
  • Acum 3 zile
  • o lună în urmă
0
adăugat editat
Dacă doriți să calculați un timp relativ de acum până la Viitor?
adăugat autor Jhonny D. Cano -Leftware-
Există pachetul .net github.com/NickStrupat/TimeAgo care face destul de mult ceea ce este solicitat.
adăugat autor Rossco
moment.js este o bibliotecă foarte potrivită pentru parsarea datei. Puteți lua în considerare utilizarea acesteia (pe partea de server sau pe partea clientului), în funcție de nevoile dvs. doar fyi pentru că nimeni nu a menționat-o aici
adăugat autor code ninja

32 răspunsuri

public static string RelativeDate(DateTime theDate)
{
    Dictionary thresholds = new Dictionary();
    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 "";
}

I prefer this version for its conciseness, and ability to add in new tick points. This could be encapsulated with a Latest() extension to Timespan instead of that long 1 liner, but for the sake of brevity in posting, this will do. This fixes the an hour ago, 1 hours ago, by providing an hour until 2 hours have elapsed

0
adăugat
Sunt obtinerea de tot felul de probleme cu ajutorul acestei funcții, de exemplu, dacă bate joc „theDate = DateTime.Now.AddMinutes (-40);“ Sunt acum '40 de ore în urmă', dar cu răspunsul lui Michael la refactormycode, se întoarce corect la '40 minute în urmă '?
adăugat autor GONeale
Pentru a remedia problema menționată de @CodeMonkeyKing, ați putea folosi un SortedDictionary în loc de un Dicționar simplu: Utilizarea este aceeași, că tastele sunt sortate. Dar chiar și atunci algoritmul are defecte, deoarece RelativeDate (DateTime.Now.AddMonths (-3) .AddDays (-3)) returnează "95 luni în urmă" tipul de dicționar pe care îl folosiți, care este incorect (ar trebui să se întoarcă acum 3 luni sau 4 luni în urmă, în funcție de pragul pe care îl utilizați) - chiar dacă -3 nu creează o dată în ultimul an ( Am testa
adăugat autor Matt
OP a uitat t.Days> 30? t.Days / 30:
adăugat autor Lars Holm Jensen
În timp ce acest cod poate funcționa, este incorect și nevalid să presupunem că ordinea tastelor din dicționar va fi într-o anumită ordine. Dicționarul folosește Object.GetHashCode () care nu returnează o perioadă lungă, ci un int !. Dacă doriți ca acestea să fie sortate, atunci ar trebui să utilizați un SortedList . Ce este în neregulă cu pragurile evaluate într-un set de if / else dacă /.../ altceva? Veți obține același număr de comparații. FYI hash-ul pentru long.MaxValue se dovedește a fi la fel ca int.MinValue!
adăugat autor CodeMonkeyKing
Cred că lipsesc un zero, încercați: de mult timp = (DateTime.Now.Ticks - theDate.Ticks) / 10000000;
adăugat autor robnardo

Iată cum fac asta

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

Sugestii? Comentarii? Modalități de îmbunătățire a acestui algoritm?

0
adăugat
În prezent, SO afișați numai formatul "Timp în urmă" până la 2 zile. Mai mult de 2 zile și ați introdus formatul standard de dată a datei. Am dreptate ?
adăugat autor Hugo Hilário
Din moment ce toate aceste funcții sunt doar oriunde, puteți crea un enum pentru o mai bună citire. Spuneți enum TimeSlabs {Seconds = 60, Minutes = 60 * 60, Ore 60 = 60 * 24, Zile = 60 * 60 * 24 * 365,
adăugat autor Antony Thomas
De asemenea, cred că este o definiție ciudată a "ieri", dacă acum (seara dimineață) văd un răspuns în seara zilei de vineri ca "ieri".
adăugat autor Paŭlo Ebermann
"<48 * 60 * 60s" este o definiție destul de neconvențională pentru "ieri". Dacă e miercuri ora 9, te-ai gândi cu adevărat la ora 9:01, luni, ca "ieri". Mi-ar fi crezut un algoritm pentru ieri sau "n zile în urmă" ar trebui să ia în considerare înainte / după miezul nopții.
adăugat autor Joe
Aș determina doar var delta = ts.Duration () pentru a obține valoarea absolută într-un obiect TimeSpan și apoi puteți face chestii ca sau dacă (delta . Încă lizibil și nu este nevoie de numere sau constante criptice.
adăugat autor Rufus L
Compilatorii sunt de obicei destul de buni la pre-calcularea expresiilor constante, cum ar fi 24 * 60 * 60, astfel încât să puteți utiliza în mod direct pe aceia în loc să-l calculați singur pentru a fi 86400 și a pune expresia originală în comentarii
adăugat autor zvolkov
@ bzlm Cred că am făcut pentru un proiect la care lucram. Motivația mea aici a fost să avertizez pe alții că săptămânile au fost omise din acest eșantion de cod. În ceea ce privește modul de a face acest lucru, mi sa părut destul de drept.
adăugat autor jray
a observat că această funcție exclude săptămâni
adăugat autor jray
Cred că o modalitate bună de îmbunătățire a algoritmului este afișarea a 2 unități cum ar fi "acum 2 luni 21 zile", "acum 1 oră și 40 de minute" pentru creșterea preciziei.
adăugat autor Evgeny Levin
@ Jeffy, ai pierdut calculul pentru anul însoțitor și verificările aferente
adăugat autor Saboor Awan
45 de minute fiind afișate ca "o oră în urmă" ?! Nu este un bug? Dacă nu este, de ce nu face același lucru pentru secunde și minute?
adăugat autor Eldritch Conundrum

@jeff

IMHO a ta pare puțin cam lungă. Cu toate acestea, pare puțin mai robust, cu sprijin pentru "ieri" și "ani". Dar, din experiența mea când este folosit, persoana este cel mai probabil să vizualizeze conținutul în primele 30 de zile. Numai oamenii cu adevărat hardcore vin după aceea. De aceea, de obicei, aleg să păstrez această scurtă și simplă.

Aceasta este metoda pe care o folosesc în mod curent pe unul dintre site-urile mele. Aceasta returnează doar o zi, o oră, o oră relativă. Și apoi utilizatorul trebuie să plesnească pe "în urmă" în ieșire.

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();
}
0
adăugat

Jeff, codul dvs. este frumos, dar ar putea fi mai clar cu constantele (așa cum este sugerat în Codul Complet).

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";
}
0
adăugat
@Atmo: nu este imposibil
adăugat autor André Pena
Chiar nu inteleg de ce oamenii nu folosesc TotalMinutes, TotalDays, TotalHours ... S-ar scurta acest lucru destul de mult ...
adăugat autor lord.fist
Are cineva vreo îndrumare cu privire la modul în care acest lucru ar putea fi implementat cu un șir de format personalizat, astfel încât "string.Format (mydate," dd / MM / yyyy (YTT) ") ==" 26/04/2011 (astăzi) "?
adăugat autor Neil Barnwell
Urăsc aceste constante cu o pasiune. Arată acest lucru greșit nimănui? Thread.Sleep (1 * MINUTE) ? Pentru că este greșit de un factor de 1000.
adăugat autor Roman Starkov
O altă eroare: Deoarece delta este absolută, calea pentru "nu încă" nu este niciodată atinsă. Schimbați la: delta = ts.TotalSeconds;
adăugat autor StefanG
Cred că dacă constantele ar fi redenumite pentru a descrie cu exactitate valoarea care este în ele, ar fi mai ușor de înțeles. Deci SecondsPerMinute = 60; MinutesPerHour = 60; SecondsPerHour = MinutesPerHour * SecondsPerHour; etc. Apelați-o doar MINUTE = 60 nu permite cititorului să determine ce este valoarea.
adăugat autor slolife
Problema este "ieri", nu este destul de precisă, deoarece ceva ce văd astăzi la ora 7 dimineața, care sa întâmplat în urmă cu două zile la ora 10 dimineața, va da "ieri", ceea ce nu este corect.
adăugat autor Ayyash
în unele limbi puteți specifica chiar orice tip de operator de comparare pentru comanda () - instrucțiune, cum ar fi>,> =, <= etc ... nu este posibil acest lucru în C #?
adăugat autor Atmocreations
De ce nu var ts = DateTime.UtcNow - yourDate; , este mai simplu? Care este justificarea pentru Math.Abs ​​?
adăugat autor Jeppe Stig Nielsen
nu ar trebui să fie dacă (delta <= 90 * MINUTE)? Cumva am primit un "acum 1 oră".
adăugat autor Roberto
De ce nimeni (cu excepția lui Joe) nu are grijă de valoarea greșită "Ieri" sau "Zile în urmă"? Ieri nu este un calcul de oră, ci un calcul zilnic. Deci da, acesta este un cod greșit cel puțin în două cazuri frecvente.
adăugat autor CtrlX
const int SECOND = 1; Atât de ciudat o secundă este o secundă.
adăugat autor seriousdev
Acest tip de cod este aproape imposibil de localizat. Dacă aplicația trebuie să rămână numai în limba engleză, atunci bine. Dar dacă faci saltul în alte limbi, te vei urî pentru că faci logică ca asta. Doar așa știți voi ...
adăugat autor Nik Reiman
@modelul Thread.Sleep (1 * MINUTE) nu îmi pare rău pentru mine și este pentru că MINUTE nu are specificate unități. Acum, MINUTE_IN_SECONDS , care ar fi ușor de identificat și ușor de stabilit: Thread.Sleep (1 * MINUTE_IN_SECONDS * 1000) sau Thread.Sleep (1 * MINUTE_IN_SECONDS * SECOND_IN_MILLISECONDS) . (Obținerea unor bug-uri verbose, dar mai bine decât ascunse.)
adăugat autor jpmc26
Când văd toată capitalul, mă gândesc la stilurile de codare dezvoltate pentru C / C ++. Recomandarea Microsoft este acoperită de Pascal. Verificați răspunsul la această întrebare - stackoverflow.com / întrebări / 242534 / & hellip;
adăugat autor CodeMonkeyKing
@nick Dacă plasați acest lucru într-un IValueConverter, acesta se va ocupa automat de CultureInfo pentru dvs. (presupunând că ați stabilit prima cultură)
adăugat autor Lance McCarthy
Puteți optimiza soluția utilizând tipul definit const pe DateTime, nu trebuie să le definiți manual.
adăugat autor SOAL ABDELDJALLIL

Am crezut că aș da o șansă folosind clase și polimorfism. Am avut o iterație anterioară, care a folosit subclasificarea, care a ajuns să fie prea mare. Am trecut la un model mai flexibil de delegat / obiect de proprietate publică, care este semnificativ mai bun. Codul meu este foarte puțin mai precis, aș vrea să pot găsi o modalitate mai bună de a genera "luni în urmă", care nu părea prea supra-inginerie.

Cred că aș rămâne în continuare cu cascada if-then a lui Jeff, pentru că este mai puțin cod și este mai simplu (este cu siguranță mai ușor să se asigure că va funcționa așa cum era de așteptat).

Pentru codul de mai jos PrintRelativeTime.GetRelativeTimeMessage (TimeSpan ago) returnează mesajul privind timpul relativ (de ex. "Ieri").

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

    static PrintRelativeTime()
    {
        timeRanges = new List{
            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);
    }
}
0
adăugat

Aș recomanda să calculați acest lucru și pe partea clientului. Mai puțin de lucru pentru server.

Următoarea este versiunea pe care o folosesc (de la 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);
                });
        };
}
0
adăugat
Întrebarea este C # etichetat De ce codul Javascript ?
adăugat autor Kiquenet

În PHP, o fac în felul următor:

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

} ?>
0
adăugat
Întrebarea este C # etichetat . De ce acest cod PHP ? IMHO, aplică numai codul C #
adăugat autor Kiquenet

@Jeff

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

Efectuarea unei scăderi la DateTime returnează oricum un TimeSpan .

Deci, puteți face

(DateTime.UtcNow - dt).TotalSeconds

Sunt, de asemenea, surprins să văd constantele înmulțite cu mâna și apoi să fie adăugate comentarii cu multiplicările. A fost oare o optimizare greșită?

0
adăugat

Asta am primit de la unul dintre blogurile lui Bill Gates. Trebuie să o găsesc în istoricul browser-ului meu și vă voi da linkul.

Codul Javascript pentru a face același lucru (după cum este cerut):

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

Practic, lucrezi în termeni de secunde ...

0
adăugat

Puteți utiliza extensia TimeAgo , din care puteți să vedeți următoarele:

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

Sau utilizați pluginul jQuery cu extensia Razor de la Timeago.

0
adăugat

Mi-ar oferi câteva metode de extensii la îndemână pentru acest lucru și să facă codul mai ușor de citit. Mai întâi, câteva metode de extensie pentru Int32 .

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

Apoi, unul pentru DateTime .

public static class DateTimeExtensions {

    public static DateTime Ago(this DateTime dateTime, TimeSpan delta) {

        return dateTime - delta;
    }
}

Acum, puteți face ceva ca mai jos:

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
0
adăugat

Aici este o rescriere din Jeff Script pentru PHP:

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";
    }
}    
0
adăugat
Întrebarea este C # etichetat De ce codul PHP ?
adăugat autor Kiquenet

using Fluent DateTime https://github.com/FluentDateTime

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();
0
adăugat

Iată algoritmul care utilizează stackoverflow, dar este rescris mai concis în pseudocod perlish cu o fixare a bug-ului (nu "acum o oră"). Funcția are un (pozitiv) număr de secunde în urmă și returnează un șir prietenos cu oamenii, cum ar fi "acum 3 ore" sau "ieri".

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";
0
adăugat
using System;
using System.Collections.Generic;
using System.Linq;

public static class RelativeDateHelper
{
    private static Dictionary> sm_Dict = null;

    private static Dictionary> DictionarySetup()
    {
        var dict = new Dictionary>();
        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;
    }
}

La fel ca un alt răspuns la această întrebare , dar ca extensie metoda cu un dicționar static.

0
adăugat
Ce vă dă dicționarul aici?
adăugat autor StriplingWarrior
Văd. Mă gândeam, deoarece documentația Dictionary afirmă că "Ordinea în care elementele returnate este nedefinită" ( msdn.microsoft.com/en-us/library/xfhwa508.aspx ) poate că nu este cea mai bună structură de date pe care să o utilizați atunci când nu vă pasă despre orele de căutare, la fel de mult ca lucrurile să rămână în ordine.
adăugat autor StriplingWarrior
StrillingWarrior: Ușurința de citire și modificare în comparație cu o declarație de switch sau o stivă de if / else. Dicționarul fiind static înseamnă că acesta și obiectele Func <,> nu trebuie să fie create de fiecare dată când dorim să folosim ToRelativeDate; este creată o singură dată, în comparație cu cea pe care am legat-o în răspunsul meu.
adăugat autor Chris Charabaruk
StriplingWarrior: Cred că LINQ ia în considerare acest lucru atunci când este folosit cu Dictionary s. Dacă încă nu sunteți de acord cu aceasta, puteți utiliza SortedDictionary , însă experiența mea arată că nu este necesar.
adăugat autor Chris Charabaruk
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";
}

Valorile de conversie pentru zile într-o lună și an au fost preluate de la Google.

0
adăugat

Cu câțiva ani mai târziu la petrecere, dar aveam o cerință de a face acest lucru atât pentru datele trecute, cât și pentru cele viitoare, așa că am combinat Jeff și Vincent's în asta. E o extravaganță 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;

        /// 
/// Returns a friendly version of the provided DateTime, relative to now. E.g.: "2 days ago", or "in 6 months". ///
 
        /// 
The DateTime to compare to Now
        /// A friendly string
        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";
            }
        }
    }
0
adăugat

Cred că există deja un număr de răspunsuri legate de acest post, dar se poate folosi acest lucru ușor de utilizat, la fel ca plugin-ul și ușor de citit de către programatori. Trimiteți data dvs. specifică și obțineți valoarea acesteia în formă de șir:

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;
}
0
adăugat

Modul meu este mult mai simplu. Aveți posibilitatea să tweak cu șiruri de întoarcere așa cum doriți

    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;
    }
0
adăugat

Cu siguranță o soluție fixă ​​pentru a scăpa de problema "acum 1 oră" ar fi să crească fereastra care este valabilă acum o oră. Schimbare

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

în

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

Acest lucru înseamnă că ceva care a avut loc acum 110 minute va fi citit "acum o oră" - poate că nu este perfect, dar aș spune că este mai bine decât situația actuală de acum 1 oră.

0
adăugat

Având în vedere că lumea și soțul ei par să elaboreze eșantioane de coduri, iată ceea ce am scris acum ceva timp, pe baza unor câteva răspunsuri.

Aveam o nevoie specifică ca acest cod să fie localizabil. Deci am două clase? Grammar , care specifică termenii localizabili și FuzzyDateExtensions , care deține o grămadă de metode de extensie. Nu aveam nevoie să mă ocup de viitoare date, așa că nu se face nici o încercare de a se ocupa de acest cod.

Am lăsat o parte din XMLdoc în sursă, dar am eliminat cel mai mult (acolo unde ar fi evident) pentru dragul scurt. De asemenea, nu am inclus nici un membru al clasei aici:

public class Grammar
{
    /// 
Gets or sets the term for "just now".
 
    public string JustNow { get; set; }
    /// 
Gets or sets the term for "X minutes ago".
 
    /// 
    ///     This is a  pattern, where {0}
    ///     is the number of minutes.
    /// 
    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; }
    /// 
Gets or sets the term for "ages ago".
 
    public string AgesAgo { get; set; }

    /// 
/// Gets or sets the threshold beyond which the fuzzy date should be /// considered "ages ago". ///
 
    public TimeSpan AgesAgoThreshold { get; set; }

    /// 
/// Initialises a new instance with the /// specified properties. ///
 
    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)
    { ... }
}

Clasa FuzzyDateString conține:

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

Unul dintre lucrurile cheie pe care am vrut să le obțin, precum și localizarea, a fost că "astăzi" ar însemna doar "această zi calendaristică", astfel încât IsToday , IsThisMonth code> Metoda IsThisYear arata astfel:

public static bool IsToday(this DateTime date)
{
    return date.DayOfYear == DateTime.Now.DayOfYear && date.IsThisYear();
}

și metodele de rotunjire sunt așa (am inclus RoundedMonths , deoarece asta este un pic diferit):

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

Sper că oamenii consideră acest lucru util și / sau interesant: o)

0
adăugat

Java pentru utilizarea gwt pe partea de client:

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

}
0
adăugat
Întrebarea este C # etichetat . De ce acest cod Java ? IMHO, aplică numai codul C #
adăugat autor Kiquenet

Există, de asemenea, un pachet numit Humanizer pe Nuget și de fapt funcționează foarte bine

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 has a writeup on it on his blog

0
adăugat
Atât de util! Acest răspuns trebuie să fie mult mai mare în această listă. Dacă aș avea 100 de voturi, aș da asta. Aparent (provenind din JS-land), căutarea acestui pachet nu a fost ușoară.
adăugat autor kumar_harsh
Notă prietenoasă: Pe .net 4.5 sau mai recent nu se instalează un utilitar complet Humanizer ... se instalează doar o parte Humanizer.Core din cauza asta ... nu se acceptă pachete de alte limbi pe această versiune
adăugat autor Ahmad

Când cunoașteți fusul orar al spectatorului, este posibil să fie mai clară utilizarea zilelor calendaristice la scara zilnică. Nu sunt familiarizat cu bibliotecile .NET, așa că nu știu cum ai face asta în C #, din păcate.

Pe site-urile de consumatori, puteți să fiți, de asemenea, în decurs de un minut. "Mai puțin de un minut în urmă" sau "chiar acum" ar putea fi destul de bun.

0
adăugat

jquery.timeago plugin

Jeff, because Stack Overflow uses jQuery extensively, I recommend the jquery.timeago plugin .

Beneficii:

  • Evitați timbrele date cu "1 minut în urmă" chiar dacă pagina a fost deschisă acum 10 minute; timeago se actualizează automat.
  • Puteți profita din plin de cache-ul de pagină și / sau fragmentare în aplicațiile dvs. web, deoarece timbrele nu sunt calculate pe server.
  • Folosiți microformate precum copiii minunați.

Doar atașați-o la timbrele tale pe DOM pregătită:

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

Aceasta va transforma toate elementele abbr intr-o clasa de timeago si un ISO 8601 marca de timp în titlul:

July 17, 2008

în ceva de genul:

4 months ago

care produce: acum 4 luni. Odată cu trecerea timpului, timestamp-urile se vor actualiza automat.

Disclaimer: Am scris acest plugin, deci sunt părtinitor.

0
adăugat
@Rob Fonseca-Ensor - acum mă face să plâng și eu. Cum se face o actualizare o dată pe minut, pentru a afișa informații exacte, în orice mod legate de text care clipește o dată pe secundă?
adăugat autor Daniel Earwicker
un plugin grozav - doar pentru distracție i-am "slăbit" prin reducerea funcționalității, cum ar fi autoupdating, și l-am combinat cu răspunsul codului refactormal </ a> - jsfiddle.net/drzaus/eMUzF
adăugat autor drzaus
Ryan, i-am sugerat ca SO sa foloseasca timeago cu ceva timp in urma. Răspunsul lui Jeff ma făcut să plâng, îți sugerez să stai jos: stackoverflow.uservoice.com/pages/1722-general/suggestions/…
adăugat autor Rob Fonseca-Ensor
@RyanMcGeary: Acesta este probabil locul greșit de întrebat, dar am o întrebare despre utilizarea TimeAgo. Sunt în Marea Britanie (GMT care include DST) și datele stocate în baza mea de date sunt UTC. Dacă aș introduce o dată în DB-ul meu ca UTC în timpul verii, în mod evident timpul va fi de 1 oră. Deci, în loc de tipărirea TimeAgo "cam acum 1 minut", se va spune "acum aproximativ o oră". Dispozitivul TimeAgo se ocupă de diferențele dintre DST?
adăugat autor TheCarver
Întrebarea este despre C #, nu reușesc să văd cum este relevant un plugin jQuery.
adăugat autor BartoszKP
Și dacă în cazul în care utilizatorul a dezactivat JavaScript? jQuery (și, în general, JavaScritp) ar trebui utilizate numai pentru a îmbunătăți experiența clientului, dar funcțiile aplicației nu ar trebui să depindă de tehnologiile clientului. Puteți realiza acest lucru fără a utiliza JavaScript.
adăugat autor Seb
O opțiune de dezactivare a actualizării automate nu ar trebui să fie atât de greu, nu-i așa? Dacă nu există deja, asta este ... Actualizați temporar marcajele de timp o dată pe pagload și faceți-le cu ea.
adăugat autor Dean Harding
face acest sprijin. c # datetime.utcNow ?? ar fi bine
adăugat autor blackholeearth0_gmail
@PaparazzoKid Da, Timeago se ocupă de fusurile orare, chiar dacă amprenta dvs. de timp este un timbru de timbru ISO8601. Dar ai dreptate. Acesta este locul greșit de a pune această întrebare. Accesați aici: github.com/rmm5t/jquery-timeago/issues
adăugat autor Ryan McGeary
Seb, dacă ai dezactivat Javascript, este afișat șirul pe care l-ai pus inițial între etichetele abbr. De obicei, aceasta este doar o dată sau o oră, în orice format doriți. Timeago se degradează cu grație. Nu este mult mai simplu.
adăugat autor Ryan McGeary
Multumesc Rob. Este în regulă. Este abia observabil, mai ales cand un singur numar se schimba in timpul tranzitiei, desi paginile SO au o multime de timbre. Mi-ar fi crezut că va fi cel puțin apreciat beneficiile cache-ului de pagină, deși, chiar dacă alege să evite auto-actualizările. Sunt sigur că Jeff ar fi putut oferi feedback pentru a îmbunătăți și plugin-ul. Îmi iau consola știind site-uri ca arstechnica.com să o folosească.
adăugat autor Ryan McGeary

Iată o implementare pe care am adăugat-o ca metodă de extensie a clasei DateTime care gestionează atât datele viitoare cât și cele trecute și oferă o opțiune de aproximare care vă permite să specificați nivelul de detaliu pe care îl căutați ("3 ore în urmă" vs "3 ore, Acum 23 minute, 12 secunde "):

using System.Text;

/// 
/// Compares a supplied date to the current date and generates a friendly English /// comparison ("5 days ago", "5 days from now") ///
 
/// 
The date to convert
/// 
When off, calculate timespan down to the second.
/// When on, approximate to the largest round unit of time.
/// 
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();
}
0
adăugat

Interfața cu iPhone-ul

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

}

0
adăugat
var ts = new TimeSpan(DateTime.Now.Ticks - dt.Ticks);
0
adăugat

puteți încerca acest lucru. Cred că va funcționa corect.

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";
}
0
adăugat
/** 
 * {@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";
    }
}
0
adăugat

Dacă doriți să aveți o ieșire cum ar fi "2 zile, 4 ore și 12 minute în urmă", aveți nevoie de o perioadă de timp:

TimeSpan timeDiff = DateTime.Now-CreatedDate;

Apoi puteți accesa valorile pe care le doriți:

timeDiff.Days
timeDiff.Hours

etc.

0
adăugat

Aceasta este funcția mea, funcționează ca un farmec :)

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;
        }
0
adăugat
Codul fericit: D
adăugat autor VnDevil
funcționează ca un farmec :)
adăugat autor densityx