Et si vous voulez calculer un temps relatif entre maintenant et le futur?
Jhonny D. Cano -Leftware-
2
moment.js est une très belle bibliothèque d'analyse de dates. Vous pouvez envisager de l'utiliser (côté serveur ou côté client), selon vos besoins. juste pour info car personne ne l'a mentionné ici
Je déteste ces constantes avec passion. Cela vous semble-t-il faux? Thread.Sleep(1 * MINUTE)? Parce que c'est faux d'un facteur 1000.
Roman Starkov
31
const int SECOND = 1;Donc, une seconde bizarre est une seconde.
seriousdev
62
Ce type de code est presque impossible à localiser. Si votre application doit uniquement rester en anglais, alors très bien. Mais si vous passez à d'autres langues, vous vous détesterez d'avoir fait une logique comme celle-ci. Pour que vous le sachiez tous ...
Nik Reiman
73
Je pense que si les constantes étaient renommées pour décrire avec précision la valeur qui s'y trouve, ce serait plus facile à comprendre. Donc SecondsPerMinute = 60; MinutesPerHour = 60; SecondsPerHour = MinutesPerHour * SecondsPerHour; etc. Le simple fait d'appeler MINUTE = 60 ne permet pas au lecteur de déterminer quelle est la valeur.
slolife
14
Pourquoi personne (sauf Joe) ne se soucie de la mauvaise valeur "Hier" ou "Il y a jours" ??? Hier n'est pas un calcul d'heure, mais un calcul de jour en jour. Alors oui, c'est un mauvais code au moins dans deux cas fréquents.
Jeff, parce que Stack Overflow utilise largement jQuery, je recommande le plugin jquery.timeago .
Avantages:
Évitez les horodatages datés de "il y a 1 minute" même si la page a été ouverte il y a 10 minutes; timeago se rafraîchit automatiquement.
Vous pouvez tirer pleinement parti de la mise en cache des pages et / ou des fragments dans vos applications Web, car les horodatages ne sont pas calculés sur le serveur.
Vous pouvez utiliser des microformats comme les enfants cool.
Attachez-le simplement à vos horodatages sur DOM ready:
Seb, Si Javascript est désactivé, la chaîne que vous avez mise à l'origine entre les balises abbr s'affiche. En règle générale, il s'agit simplement d'une date ou d'une heure dans le format de votre choix. Timeago se dégrade gracieusement. Cela ne devient pas beaucoup plus simple.
Hé, merci Rob. C'est bon. C'est à peine perceptible, surtout quand un seul numéro change pendant la transition, bien que les pages SO aient beaucoup d'horodatages. J'aurais pensé qu'il aurait au moins apprécié les avantages de la mise en cache des pages, même s'il choisissait d'éviter les mises à jour automatiques. Je suis sûr que Jeff aurait également pu fournir des commentaires pour améliorer le plugin. Je prends du réconfort en sachant que des sites comme arstechnica.com l' utilisent.
Ryan McGeary
19
@Rob Fonseca-Ensor - maintenant ça me fait aussi pleurer. Comment est une mise à jour une fois par minute, pour afficher des informations précises, en rapport avec le clignotement du texte une fois par seconde?
Daniel Earwicker
25
La question concerne C #, je ne vois pas en quoi un plugin jQuery est pertinent.
"<48 * 60 * 60s" est une définition plutôt non conventionnelle pour "hier". Si c'est 9h mercredi, pensez-vous vraiment à 9h01 lundi comme "hier". J'aurais pensé qu'un algorithme pour hier ou "il y a n jours" devrait envisager avant / après minuit.
Joe
139
Les compilateurs sont généralement assez bons pour pré-calculer des expressions constantes, comme 24 * 60 * 60, vous pouvez donc les utiliser directement au lieu de les calculer vous-même à 86400 et de mettre l'expression originale dans les commentaires
zvolkov
11
@bzlm Je pense l'avoir fait pour un projet sur lequel je travaillais. Ma motivation ici était d'alerter les autres que des semaines avaient été omises de cet exemple de code. Quant à la façon de procéder, cela m'a semblé assez simple.
jray
9
Je pense que le bon moyen d'améliorer l'algorithme est d'afficher 2 unités comme "il y a 2 mois 21 jours", "il y a 1 heure 40 minutes" pour augmenter la précision.
Evgeny Levin
5
@ Jeffy, vous avez manqué le calcul pour l'année bissextile et les contrôles associés
Saboor Awan
92
publicstaticstringRelativeDate(DateTime theDate){Dictionary<long,string> thresholds =newDictionary<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 =newTimeSpan((DateTime.Now.Ticks- theDate.Ticks));returnstring.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"";}
Je préfère cette version pour sa concision et sa capacité à ajouter de nouveaux points de tick. Cela pourrait être encapsulé avec une Latest()extension de Timespan au lieu de cette longue ligne 1, mais pour des raisons de brièveté dans la publication, cela suffira.
Cela corrige il y a une heure, il y a 1 heures, en prévoyant une heure jusqu'à ce que 2 heures se soient écoulées
Je reçois toutes sortes de problèmes en utilisant cette fonction, par exemple si vous vous moquez de 'theDate = DateTime.Now.AddMinutes (-40);' Je reçois «il y a 40 heures», mais avec la réponse refactormycode de Michael, il revient correctement à «il y a 40 minutes»?
GONeale
je pense que vous manquez un zéro, essayez: depuis longtemps = (DateTime.Now.Ticks - theDate.Ticks) / 10000000;
robnardo
8
Hmm, bien que ce code puisse fonctionner, il est incorrect et non valide de supposer que l'ordre des clés dans le dictionnaire sera dans un ordre spécifique. Le dictionnaire utilise Object.GetHashCode () qui ne renvoie pas un long mais un int !. Si vous souhaitez que ces éléments soient triés, vous devez utiliser un SortedList <long, string>. Quel est le problème avec les seuils évalués dans un ensemble de if / else if /.../ else? Vous obtenez le même nombre de comparaisons. Pour info le hachage pour long.MaxValue s'avère être le même que int.MinValue!
CodeMonkeyKing
OP oublié t.Days> 30? t.Days / 30:
Lars Holm Jensen
Pour résoudre le problème mentionné par @CodeMonkeyKing, vous pouvez utiliser un SortedDictionaryau lieu d'un simple Dictionary: l'utilisation est la même, mais elle garantit que les clés sont triées. Mais même dans ce cas, l'algorithme a des défauts, car RelativeDate(DateTime.Now.AddMonths(-3).AddDays(-3))renvoie "il y a 95 mois" , quel que soit le type de dictionnaire que vous utilisez, ce qui est incorrect (il devrait renvoyer "il y a 3 mois" ou "il y a 4 mois" selon le seuil que vous ' réutilisation) - même si -3 ne crée pas de date au cours de la dernière année (j'ai testé cela en décembre, donc dans ce cas cela ne devrait pas se produire).
staticreadonlySortedList<double,Func<TimeSpan,string>> offsets =newSortedList<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"}};publicstaticstringToRelativeDate(thisDateTime input){TimeSpan x =DateTime.Now- input;stringSuffix= x.TotalMinutes>0?" ago":" from now";
x =newTimeSpan(Math.Abs(x.Ticks));return offsets.First(n => x.TotalMinutes< n.Key).Value(x)+Suffix;}
c'est très agréable IMO :) Cela pourrait également être refactorisé comme une méthode d'extension? le dictionnaire pourrait-il devenir statique de sorte qu'il n'est créé qu'une seule fois et référencé par la suite?
Vous voudrez probablement extraire ce dictionnaire dans un champ afin de réduire l'instanciation et le désabonnement GC. Vous devez changer Func<string>pour Func<double>.
Drew Noakes
49
Voici une implémentation que j'ai ajoutée comme méthode d'extension à la classe DateTime qui gère à la fois les dates futures et passées et fournit une option d'approximation qui vous permet de spécifier le niveau de détail que vous recherchez ("il y a 3 heures" vs "3 heures, Il y a 23 minutes, 12 secondes "):
usingSystem.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>publicstaticstringToRelativeDateString(thisDateTimevalue,bool approximate){StringBuilder sb =newStringBuilder();string suffix =(value>DateTime.Now)?" from now":" ago";TimeSpan timeSpan =newTimeSpan(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();}
note amicale: sur .net 4.5 ou supérieur, n'installez pas Humanizer complet ... installez uniquement Humanizer.Core en partie .. car les autres packages de langue ne sont pas pris en charge sur cette version
Ahmad
Tellement utile! Cette réponse doit être beaucoup plus élevée dans cette liste. Si j'avais 100 voix, je donnerais cela. Apparemment (venant de JS-land), la recherche de ce package n'a pas été facile.
kumarharsh
29
@jeff
À mon humble avis, le vôtre semble un peu long. Cependant, il semble un peu plus robuste avec un support pour "hier" et "années". Mais d'après mon expérience, lorsque cette option est utilisée, la personne est plus susceptible de voir le contenu au cours des 30 premiers jours. Ce ne sont que les gens vraiment hardcore qui viennent après ça. C'est pourquoi je choisis généralement de garder cela court et simple.
C'est la méthode que j'utilise actuellement sur l'un de mes sites Web. Cela ne renvoie qu'un jour, une heure et une heure relatifs. Et puis l'utilisateur doit gifler "il y a" dans la sortie.
Quelques années de retard à la fête, mais j'avais une obligation de le faire pour les dates passées et futures, j'ai donc combiné Jeff et Vincent à cela. C'est une extravagance ternarytastique! :)
publicstaticclassDateTimeHelper{privateconstint SECOND =1;privateconstint MINUTE =60* SECOND;privateconstint HOUR =60* MINUTE;privateconstint DAY =24* HOUR;privateconstint 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>publicstaticstringGetFriendlyRelativeTime(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?newTimeSpan(dateTime.Ticks-DateTime.UtcNow.Ticks):newTimeSpan(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";}}}
Étant donné que le monde et son mari semblent publier des exemples de code, voici ce que j'ai écrit il y a quelque temps, basé sur quelques-unes de ces réponses.
J'avais un besoin spécifique pour que ce code soit localisable. J'ai donc deux classes - Grammar, qui spécifie les termes localisables, et FuzzyDateExtensions, qui contient un tas de méthodes d'extension. Je n'avais pas besoin de m'occuper des futures datetimes, donc aucune tentative n'est faite pour les gérer avec ce code.
J'ai laissé une partie du XMLdoc dans la source, mais j'ai supprimé la plupart (où ils seraient évidents) par souci de concision. Je n'ai pas non plus inclus tous les membres de la classe ici:
publicclassGrammar{/// <summary> Gets or sets the term for "just now". </summary>publicstringJustNow{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>publicstringMinutesAgo{get;set;}publicstringOneHourAgo{get;set;}publicstringHoursAgo{get;set;}publicstringYesterday{get;set;}publicstringDaysAgo{get;set;}publicstringLastMonth{get;set;}publicstringMonthsAgo{get;set;}publicstringLastYear{get;set;}publicstringYearsAgo{get;set;}/// <summary> Gets or sets the term for "ages ago". </summary>publicstringAgesAgo{get;set;}/// <summary>/// Gets or sets the threshold beyond which the fuzzy date should be/// considered "ages ago"./// </summary>publicTimeSpanAgesAgoThreshold{get;set;}/// <summary>/// Initialises a new <see cref="Grammar"/> instance with the/// specified properties./// </summary>privatevoidInitialise(string justNow,string minutesAgo,string oneHourAgo,string hoursAgo,string yesterday,string daysAgo,string lastMonth,string monthsAgo,string lastYear,string yearsAgo,string agesAgo,TimeSpan agesAgoThreshold){...}}
L' une des principales choses que je voulais réaliser, ainsi que la localisation, était que « aujourd'hui » ne ferait que dire « ce jour de calendrier », de sorte que le IsToday, IsThisMonth, les IsThisYearméthodes ressemblent à ceci:
Je pensais que je pourrais essayer ceci en utilisant des classes et le polymorphisme. J'ai eu une itération précédente qui utilisait la sous-classification qui a fini par avoir beaucoup trop de frais généraux. Je suis passé à un modèle d'objet délégué / propriété publique plus flexible, ce qui est nettement meilleur. Mon code est très légèrement plus précis, j'aurais aimé pouvoir trouver une meilleure façon de générer des "mois passés" qui ne semblaient pas trop sur-conçus.
Je pense que je resterais avec la cascade if-then de Jeff car c'est moins de code et c'est plus simple (il est certainement plus facile de s'assurer que cela fonctionnera comme prévu).
Pour le code ci-dessous PrintRelativeTime.GetRelativeTimeMessage (TimeSpan ago) renvoie le message d'heure relative (par exemple "hier").
publicclassRelativeTimeRange:IComparable{publicTimeSpanUpperBound{get;set;}publicdelegatestringRelativeTimeTextDelegate(TimeSpan timeDelta);publicRelativeTimeTextDelegateMessageCreator{get;set;}publicintCompareTo(object obj){if(!(obj isRelativeTimeRange)){return1;}// note that this sorts in reverse order to the way you'd expect, // this saves having to reverse a list laterreturn(obj asRelativeTimeRange).UpperBound.CompareTo(UpperBound);}}publicclassPrintRelativeTime{privatestaticList<RelativeTimeRange> timeRanges;staticPrintRelativeTime(){
timeRanges =newList<RelativeTimeRange>{newRelativeTimeRange{UpperBound=TimeSpan.FromSeconds(1),MessageCreator=(delta)=>{return"one second ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromSeconds(60),MessageCreator=(delta)=>{return delta.Seconds+" seconds ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromMinutes(2),MessageCreator=(delta)=>{return"one minute ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromMinutes(60),MessageCreator=(delta)=>{return delta.Minutes+" minutes ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromHours(2),MessageCreator=(delta)=>{return"one hour ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromHours(24),MessageCreator=(delta)=>{return delta.Hours+" hours ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromDays(2),MessageCreator=(delta)=>{return"yesterday";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddMonths(-1)),MessageCreator=(delta)=>{return delta.Days+" days ago";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddMonths(-2)),MessageCreator=(delta)=>{return"one month ago";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddYears(-1)),MessageCreator=(delta)=>{return(int)Math.Floor(delta.TotalDays/30)+" months ago";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddYears(-2)),MessageCreator=(delta)=>{return"one year ago";}},newRelativeTimeRange{UpperBound=TimeSpan.MaxValue,MessageCreator=(delta)=>{return(int)Math.Floor(delta.TotalDays/365.24D)+" years ago";}}};
timeRanges.Sort();}publicstaticstringGetRelativeTimeMessage(TimeSpan ago){RelativeTimeRange postRelativeDateRange = timeRanges[0];foreach(var timeRange in timeRanges){if(ago.CompareTo(timeRange.UpperBound)<=0){
postRelativeDateRange = timeRange;}}return postRelativeDateRange.MessageCreator(ago);}}
StriplingWarrior: facilité de lecture et de modification par rapport à une instruction switch ou à une pile d'instructions if / else. Le dictionnaire étant statique signifie que lui et les objets Func <,> ne doivent pas être créés à chaque fois que nous voulons utiliser ToRelativeDate; il n'est créé qu'une seule fois, par rapport à celui que j'ai lié dans ma réponse.
Chris Charabaruk
Je vois. Je pensais juste, car la documentation sur Dictionaryindique que "L'ordre dans lequel les éléments sont renvoyés n'est pas défini", ( msdn.microsoft.com/en-us/library/xfhwa508.aspx ) ce n'est peut-être pas la meilleure structure de données à utiliser lorsque vous ne vous souciez pas autant des temps de recherche que du maintien de l'ordre.
StriplingWarrior
StriplingWarrior: Je crois que LINQ en tient compte lorsqu'il est utilisé avec l' Dictionaryart. Si vous n'êtes toujours pas à l'aise avec cela, vous pouvez l'utiliser SortedDictionary, mais ma propre expérience montre que cela n'est pas nécessaire.
Chris Charabaruk
12
Lorsque vous connaissez le fuseau horaire du spectateur, il peut être plus clair d'utiliser les jours civils à l'échelle du jour. Je ne connais pas les bibliothèques .NET, donc je ne sais pas comment vous feriez cela en C #, malheureusement.
Sur les sites de consommateurs, vous pourriez également être manié à la main en moins d'une minute. "Il y a moins d'une minute" ou "tout à l'heure" pourrait être suffisant.
La question est balisée C # . Pourquoi ce code Java ? À
mon humble avis
9
@Jeff
var ts =newTimeSpan(DateTime.UtcNow.Ticks- dt.Ticks);
Faire une soustraction sur DateTimerenvoie TimeSpanquand même un .
Vous pouvez donc faire
(DateTime.UtcNow- dt).TotalSeconds
Je suis également surpris de voir les constantes multipliées à la main, puis les commentaires ajoutés avec les multiplications. Était-ce une optimisation erronée?
Voici l'algorithme utilisé par stackoverflow mais réécrit de manière plus concise en pseudocode perlish avec une correction de bogue (pas "il y a" une heure "). La fonction prend un nombre (positif) de secondes auparavant et renvoie une chaîne conviviale comme "il y a 3 heures" ou "hier".
Vous pouvez utiliser l' extension TimeAgo à partir de laquelle ressemble à ceci:
publicstaticstringTimeAgo(thisDateTime dateTime){string result =string.Empty;var timeSpan =DateTime.Now.Subtract(dateTime);if(timeSpan <=TimeSpan.FromSeconds(60)){
result =string.Format("{0} seconds ago", timeSpan.Seconds);}elseif(timeSpan <=TimeSpan.FromMinutes(60)){
result = timeSpan.Minutes>1?String.Format("about {0} minutes ago", timeSpan.Minutes):"about a minute ago";}elseif(timeSpan <=TimeSpan.FromHours(24)){
result = timeSpan.Hours>1?String.Format("about {0} hours ago", timeSpan.Hours):"about an hour ago";}elseif(timeSpan <=TimeSpan.FromDays(30)){
result = timeSpan.Days>1?String.Format("about {0} days ago", timeSpan.Days):"yesterday";}elseif(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;}
Ou utilisez le plugin jQuery avec l'extension Razor de Timeago.
Vous pouvez réduire la charge côté serveur en effectuant cette logique côté client. Voir la source sur certaines pages Digg pour référence. Ils ont le serveur émettre une valeur de temps d'époque qui est traitée par Javascript. De cette façon, vous n'avez pas besoin de gérer le fuseau horaire de l'utilisateur final. Le nouveau code côté serveur ressemblerait à ceci:
Ça, je l'ai reçu d'un des blogs de Bill Gates. Je dois le trouver dans l'historique de mon navigateur et je vous donnerai le lien.
Le code Javascript pour faire la même chose (comme demandé):
function posted(t){var now =newDate();var diff = parseInt((now.getTime()-Date.parse(t))/1000);if(diff <60){return'less than a minute ago';}elseif(diff <120){return'about a minute ago';}elseif(diff <(2700)){return(parseInt(diff /60)).toString()+' minutes ago';}elseif(diff <(5400)){return'about an hour ago';}elseif(diff <(86400)){return'about '+(parseInt(diff /3600)).toString()+' hours ago';}elseif(diff <(172800)){return'1 day ago';}else{return(parseInt(diff /86400)).toString()+' days ago';}}
Fondamentalement, vous travaillez en termes de secondes ...
Je pense qu'il y a déjà un certain nombre de réponses liées à ce post, mais on peut utiliser cela qui est facile à utiliser comme un plugin et également facilement lisible pour les programmeurs. Envoyez votre date spécifique et obtenez sa valeur sous forme de chaîne:
Je fournirais quelques méthodes d'extensions pratiques pour cela et rendrais le code plus lisible. Tout d'abord, quelques méthodes d'extension pour Int32.
Réponses:
Jeff, votre code est agréable mais pourrait être plus clair avec des constantes (comme suggéré dans Code Complete).
la source
Thread.Sleep(1 * MINUTE)
? Parce que c'est faux d'un facteur 1000.const int SECOND = 1;
Donc, une seconde bizarre est une seconde.plugin jquery.timeago
Jeff, parce que Stack Overflow utilise largement jQuery, je recommande le plugin jquery.timeago .
Avantages:
Attachez-le simplement à vos horodatages sur DOM ready:
Cela transformera tous les
abbr
éléments avec une classe de timeago et un horodatage ISO 8601 dans le titre:en quelque chose comme ça:
qui donne: il y a 4 mois. Au fil du temps, les horodatages seront automatiquement mis à jour.
Avertissement: j'ai écrit ce plugin, donc je suis partial.
la source
Voici comment je le fais
Suggestions? Commentaires? Comment améliorer cet algorithme?
la source
Je préfère cette version pour sa concision et sa capacité à ajouter de nouveaux points de tick. Cela pourrait être encapsulé avec une
Latest()
extension de Timespan au lieu de cette longue ligne 1, mais pour des raisons de brièveté dans la publication, cela suffira. Cela corrige il y a une heure, il y a 1 heures, en prévoyant une heure jusqu'à ce que 2 heures se soient écouléesla source
SortedDictionary
au lieu d'un simpleDictionary
: l'utilisation est la même, mais elle garantit que les clés sont triées. Mais même dans ce cas, l'algorithme a des défauts, carRelativeDate(DateTime.Now.AddMonths(-3).AddDays(-3))
renvoie "il y a 95 mois" , quel que soit le type de dictionnaire que vous utilisez, ce qui est incorrect (il devrait renvoyer "il y a 3 mois" ou "il y a 4 mois" selon le seuil que vous ' réutilisation) - même si -3 ne crée pas de date au cours de la dernière année (j'ai testé cela en décembre, donc dans ce cas cela ne devrait pas se produire).Voici une réécriture de Jeffs Script pour PHP:
la source
http://refactormycode.com/codes/493-twitter-esque-relative-dates
Version C # 6:
la source
Func<string>
pourFunc<double>
.Voici une implémentation que j'ai ajoutée comme méthode d'extension à la classe DateTime qui gère à la fois les dates futures et passées et fournit une option d'approximation qui vous permet de spécifier le niveau de détail que vous recherchez ("il y a 3 heures" vs "3 heures, Il y a 23 minutes, 12 secondes "):
la source
Je recommanderais également de calculer cela du côté client. Moins de travail pour le serveur.
Ce qui suit est la version que j'utilise (de Zach Leatherman)
la source
Il existe également un package appelé Humanizr sur Nuget, qui fonctionne réellement très bien et se trouve dans la .NET Foundation.
Scott Hanselman a un article à ce sujet sur son blog
la source
@jeff
À mon humble avis, le vôtre semble un peu long. Cependant, il semble un peu plus robuste avec un support pour "hier" et "années". Mais d'après mon expérience, lorsque cette option est utilisée, la personne est plus susceptible de voir le contenu au cours des 30 premiers jours. Ce ne sont que les gens vraiment hardcore qui viennent après ça. C'est pourquoi je choisis généralement de garder cela court et simple.
C'est la méthode que j'utilise actuellement sur l'un de mes sites Web. Cela ne renvoie qu'un jour, une heure et une heure relatifs. Et puis l'utilisateur doit gifler "il y a" dans la sortie.
la source
Quelques années de retard à la fête, mais j'avais une obligation de le faire pour les dates passées et futures, j'ai donc combiné Jeff et Vincent à cela. C'est une extravagance ternarytastique! :)
la source
Existe-t-il un moyen simple de le faire en Java? La
java.util.Date
classe semble plutôt limitée.Voici ma solution Java rapide et sale:
la source
Version iPhone Objective-C
la source
Étant donné que le monde et son mari semblent publier des exemples de code, voici ce que j'ai écrit il y a quelque temps, basé sur quelques-unes de ces réponses.
J'avais un besoin spécifique pour que ce code soit localisable. J'ai donc deux classes -
Grammar
, qui spécifie les termes localisables, etFuzzyDateExtensions
, qui contient un tas de méthodes d'extension. Je n'avais pas besoin de m'occuper des futures datetimes, donc aucune tentative n'est faite pour les gérer avec ce code.J'ai laissé une partie du XMLdoc dans la source, mais j'ai supprimé la plupart (où ils seraient évidents) par souci de concision. Je n'ai pas non plus inclus tous les membres de la classe ici:
La
FuzzyDateString
classe contient:L' une des principales choses que je voulais réaliser, ainsi que la localisation, était que « aujourd'hui » ne ferait que dire « ce jour de calendrier », de sorte que le
IsToday
,IsThisMonth
, lesIsThisYear
méthodes ressemblent à ceci:et les méthodes d'arrondi sont comme ceci (j'ai inclus
RoundedMonths
, car c'est un peu différent):J'espère que les gens trouveront cela utile et / ou intéressant: o)
la source
En PHP, je le fais de cette façon:
la source
en utilisant Fluent DateTime
la source
Je pensais que je pourrais essayer ceci en utilisant des classes et le polymorphisme. J'ai eu une itération précédente qui utilisait la sous-classification qui a fini par avoir beaucoup trop de frais généraux. Je suis passé à un modèle d'objet délégué / propriété publique plus flexible, ce qui est nettement meilleur. Mon code est très légèrement plus précis, j'aurais aimé pouvoir trouver une meilleure façon de générer des "mois passés" qui ne semblaient pas trop sur-conçus.
Je pense que je resterais avec la cascade if-then de Jeff car c'est moins de code et c'est plus simple (il est certainement plus facile de s'assurer que cela fonctionnera comme prévu).
Pour le code ci-dessous PrintRelativeTime.GetRelativeTimeMessage (TimeSpan ago) renvoie le message d'heure relative (par exemple "hier").
la source
Identique à une autre réponse à cette question mais comme méthode d'extension avec un dictionnaire statique.
la source
Dictionary
indique que "L'ordre dans lequel les éléments sont renvoyés n'est pas défini", ( msdn.microsoft.com/en-us/library/xfhwa508.aspx ) ce n'est peut-être pas la meilleure structure de données à utiliser lorsque vous ne vous souciez pas autant des temps de recherche que du maintien de l'ordre.Dictionary
art. Si vous n'êtes toujours pas à l'aise avec cela, vous pouvez l'utiliserSortedDictionary
, mais ma propre expérience montre que cela n'est pas nécessaire.Lorsque vous connaissez le fuseau horaire du spectateur, il peut être plus clair d'utiliser les jours civils à l'échelle du jour. Je ne connais pas les bibliothèques .NET, donc je ne sais pas comment vous feriez cela en C #, malheureusement.
Sur les sites de consommateurs, vous pourriez également être manié à la main en moins d'une minute. "Il y a moins d'une minute" ou "tout à l'heure" pourrait être suffisant.
la source
vous pouvez essayer cela. Je pense que cela fonctionnera correctement.
la source
Java pour une utilisation gwt côté client:
la source
@Jeff
Faire une soustraction sur
DateTime
renvoieTimeSpan
quand même un .Vous pouvez donc faire
Je suis également surpris de voir les constantes multipliées à la main, puis les commentaires ajoutés avec les multiplications. Était-ce une optimisation erronée?
la source
Voici l'algorithme utilisé par stackoverflow mais réécrit de manière plus concise en pseudocode perlish avec une correction de bogue (pas "il y a" une heure "). La fonction prend un nombre (positif) de secondes auparavant et renvoie une chaîne conviviale comme "il y a 3 heures" ou "hier".
la source
Vous pouvez utiliser l' extension TimeAgo à partir de laquelle ressemble à ceci:
Ou utilisez le plugin jQuery avec l'extension Razor de Timeago.
la source
Vous pouvez réduire la charge côté serveur en effectuant cette logique côté client. Voir la source sur certaines pages Digg pour référence. Ils ont le serveur émettre une valeur de temps d'époque qui est traitée par Javascript. De cette façon, vous n'avez pas besoin de gérer le fuseau horaire de l'utilisateur final. Le nouveau code côté serveur ressemblerait à ceci:
Vous pouvez même y ajouter un bloc NOSCRIPT et simplement effectuer une ToString ().
la source
Ça, je l'ai reçu d'un des blogs de Bill Gates. Je dois le trouver dans l'historique de mon navigateur et je vous donnerai le lien.
Le code Javascript pour faire la même chose (comme demandé):
Fondamentalement, vous travaillez en termes de secondes ...
la source
Je pense qu'il y a déjà un certain nombre de réponses liées à ce post, mais on peut utiliser cela qui est facile à utiliser comme un plugin et également facilement lisible pour les programmeurs. Envoyez votre date spécifique et obtenez sa valeur sous forme de chaîne:
la source
la source
Si vous voulez avoir une sortie comme
"2 days, 4 hours and 12 minutes ago"
, vous avez besoin d'une période de temps:Ensuite, vous pouvez accéder aux valeurs que vous aimez:
etc...
la source
Je fournirais quelques méthodes d'extensions pratiques pour cela et rendrais le code plus lisible. Tout d'abord, quelques méthodes d'extension pour
Int32
.Ensuite, un pour
DateTime
.Maintenant, vous pouvez faire quelque chose comme ci-dessous:
la source