Algoritmo de fecha borrosa
-
03-07-2019 - |
Pregunta
Estoy buscando un algoritmo de fecha borrosa. Acabo de empezar a escribir uno y me di cuenta de lo tediosa que es la tarea. Se degeneró rápidamente en un montón de código horrible para hacer frente a casos especiales como la diferencia entre "ayer", "semana pasada" y " finales del mes pasado " todo lo cual puede (en algunos casos) referirse al mismo día pero son correctos individualmente según la fecha de hoy.
Estoy seguro de que debe haber un formateador de fecha difuso de código abierto, pero no puedo encontrarlo. Idealmente, me gustaría algo que use NSDate (OSX / iPhone) y sus formateadores, pero eso no es lo difícil. ¿Alguien sabe de un formateador de fecha difuso que tome algún período de tiempo en relación con ahora y devuelva una cadena como (pero no limitada a):
- hace unos momentos
- en los últimos cinco minutos
- anteriormente hoy
- esta mañana
- anoche
- la semana pasada
- el pasado miércoles
- a principios del mes pasado
- junio del año pasado
- hace un par de años
En un mundo ideal, me gustaría que la cadena fuera lo más rica posible (es decir, que devuelva variantes aleatorias en " Hace un momento " como " justo ahora ").
Aclaración. Estoy buscando algo más sutil que las hebillas y cuerdas básicas. Quiero algo que sepa " ayer " y " el pasado miércoles " ambos pueden referirse al mismo período, pero solo uno es correcto cuando hoy es jueves.
Solución
Esta pregunta lo ayudará a comenzar. Tiene el código muy presente. El sitio utiliza para calcular su tiempo relativo. Puede que no tenga los rangos específicos que desea, pero son fáciles de agregar una vez que los haya configurado.
Otros consejos
Hay una propiedad en NSDateFormatter - " doesRelativeDateFormatting " ;. Aparece solo en 10.6 / iOS4.0 y versiones posteriores, pero formateará una fecha en una fecha relativa en la ubicación correcta.
Si un formateador de fecha usa fecha relativa formateo, donde sea posible reemplaza El componente de fecha de su salida con una frase & # 8212; como & # 8220; today & # 8221; o & # 8220; mañana & # 8221; & # 8212; eso indica un familiar fecha. Las frases disponibles dependen de el entorno local para el formateador de fecha; Considerando que, para fechas en el futuro, El inglés solo puede permitir & # 8220; mañana, & # 8221; Francés puede permitir & # 8220; el día después de la pasado mañana, & # 8221; como se ilustra en el siguiente ejemplo.
Código
El siguiente es un código que imprimirá un buen número de las cadenas relativas para una ubicación determinada.
NSLocale *locale = [NSLocale currentLocale];
// NSLocale *locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"fr_FR"] autorelease];
NSDateFormatter *relativeDateFormatter = [[NSDateFormatter alloc] init];
[relativeDateFormatter setTimeStyle:NSDateFormatterNoStyle];
[relativeDateFormatter setDateStyle:NSDateFormatterMediumStyle];
[relativeDateFormatter setDoesRelativeDateFormatting:YES];
[relativeDateFormatter setLocale:locale];
NSDateFormatter *normalDateFormatter = [[NSDateFormatter alloc] init];
[normalDateFormatter setTimeStyle:NSDateFormatterNoStyle];
[normalDateFormatter setDateStyle:NSDateFormatterMediumStyle];
[normalDateFormatter setDoesRelativeDateFormatting:NO];
[normalDateFormatter setLocale:locale];
NSString * lastUniqueString = nil;
for ( NSTimeInterval timeInterval = -60*60*24*400; timeInterval < 60*60*24*400; timeInterval += 60.0*60.0*24.0 )
{
NSDate * date = [NSDate dateWithTimeIntervalSinceNow:timeInterval];
NSString * relativeFormattedString = [relativeDateFormatter stringForObjectValue:date];
NSString * formattedString = [normalDateFormatter stringForObjectValue:date];
if ( [relativeFormattedString isEqualToString:lastUniqueString] || [relativeFormattedString isEqualToString:formattedString] )
continue;
NSLog( @"%@", relativeFormattedString );
lastUniqueString = relativeFormattedString;
}
Notas:
- No se requiere una configuración regional
- Hay no hay tantas sustituciones para Inglés. En el momento de escribir allí. son: " Ayer, Hoy, Mañana " ;. Apple puede incluir más en el futuro.
- Es divertido cambiar la configuración regional y ver lo que está disponible en otros idiomas (El francés tiene algo más que el inglés, por ejemplo)
- Si está en iOS, puede que desee suscribirse a UIApplicationSignificantTimeChangeNotification
Interface Builder
Puedes configurar el " doesRelativeDateFormatting " propiedad en Interface Builder:
- Seleccione su NSDateFormatter y seleccione el " Inspector de identidad " lengüeta de la paleta de inspectores (la última uno [comando-6]).
- En la subsección denominada "Usuario" Atributos de tiempo de ejecución definidos " ;, puede agregue su propio valor para una clave en el objeto seleccionado (en este caso, su instancia de NSDateFormatter). Añadir " doesRelativeDateFormatting " ;, elige un " Boolean " escriba y asegúrese de que es revisado.
- Recuerde : puede parecer que no funcionó en absoluto, pero eso podría deberse a que solo hay unos pocos valores sustituidos para la configuración regional. Pruebe al menos una fecha para Ayer, Hoy y Mañana antes de decidir si no está bien configurado.
Es posible que desee consultar la función distance_of_time_in_words
de Rail en date_helper.rb , que he pegado a continuación.
# File vendor/rails/actionpack/lib/action_view/helpers/date_helper.rb, line 59
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
from_time = from_time.to_time if from_time.respond_to?(:to_time)
to_time = to_time.to_time if to_time.respond_to?(:to_time)
distance_in_minutes = (((to_time - from_time).abs)/60).round
distance_in_seconds = ((to_time - from_time).abs).round
I18n.with_options :locale => options[:locale], :scope => 'datetime.distance_in_words''datetime.distance_in_words' do |locale|
case distance_in_minutes
when 0..1
return distance_in_minutes == 0 ?
locale.t(:less_than_x_minutes, :count => 1) :
locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds
case distance_in_seconds
when 0..4 then locale.t :less_than_x_seconds, :count => 5
when 5..9 then locale.t :less_than_x_seconds, :count => 10
when 10..19 then locale.t :less_than_x_seconds, :count => 20
when 20..39 then locale.t :half_a_minute
when 40..59 then locale.t :less_than_x_minutes, :count => 1
else locale.t :x_minutes, :count => 1
end
when 2..44 then locale.t :x_minutes, :count => distance_in_minutes
when 45..89 then locale.t :about_x_hours, :count => 1
when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
when 1440..2879 then locale.t :x_days, :count => 1
when 2880..43199 then locale.t :x_days, :count => (distance_in_minutes / 1440).round
when 43200..86399 then locale.t :about_x_months, :count => 1
when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes / 43200).round
when 525600..1051199 then locale.t :about_x_years, :count => 1
else locale.t :over_x_years, :count => (distance_in_minutes / 525600).round
end
end
end
Entonces, aquí está la categoría que escribí en NSDate para aquellos que aún están interesados. El problema es uno de los que se vuelve un poco quijotesco. Básicamente es una enorme declaración de conmutación (aunque la implementé en una serie de cascada si () s para que sea más legible.
Para cada período de tiempo, a continuación, selecciono entre un conjunto aleatorio de formas de decir la hora.
En general, esto encantó a algunos de nuestros usuarios, pero no estoy seguro de que valga la pena el esfuerzo.
NSTimeInterval const kTenSeconds = (10.0f );
NSTimeInterval const kOneMinute = (60.0f);
NSTimeInterval const kFiveMinutes = (5.0f*60.0f);
NSTimeInterval const kFifteenMinutes = (15.0f*60.0f) ;
NSTimeInterval const kHalfAnHour = (30.0f*60.0f) ;
NSTimeInterval const kOneHour = 3600.0f; // (60.0f * 60.0f);
NSTimeInterval const kHalfADay = (3600.0f * 12.0f);
NSTimeInterval const kOneDay = (3600.0f * 24.0f);
NSTimeInterval const kOneWeek = (3600.0f * 24.0f * 7.0f);
@implementation NSDate (Fuzzy)
-(NSString*)fuzzyStringRelativeToNow;
{
static NSArray* secondsStrings;
static NSArray* minuteStrings;
static NSArray* fiveMinuteStrings;
static NSArray* halfHourStrings;
static NSArray* earlyMonthStrings;
NSTimeInterval timeFromNow = [self timeIntervalSinceNow];
if((timeFromNow < 0)) // In the past
{
timeFromNow = - timeFromNow;
if ( (timeFromNow < kTenSeconds))
{
if(!secondsStrings)
{
secondsStrings = [[NSArray arrayWithObjects:@"just now",
//@"a few seconds ago",
//@"right this instant",
@"moments ago",
nil] retain];
}
unsigned int index = random() % ([secondsStrings count] - 1);
return [secondsStrings objectAtIndex:index];
}
if ( (timeFromNow < kOneMinute))
{
if(!minuteStrings)
{
minuteStrings = [[NSArray arrayWithObjects:@"just now",
@"very recently",
@"in the last minute",
nil] retain];
}
unsigned int index = random() % ([minuteStrings count] - 1);
return [minuteStrings objectAtIndex:index];
}
if (timeFromNow < kFiveMinutes)
{
if(!fiveMinuteStrings)
{
fiveMinuteStrings = [[NSArray arrayWithObjects:@"just now",
@"very recently",
//@"in the last minute",
@"a few minutes ago",
//@"in the last five minutes",
nil] retain];
}
unsigned int index = random() % ([fiveMinuteStrings count] - 1);
return [fiveMinuteStrings objectAtIndex:index];
}
if (timeFromNow < kFifteenMinutes)
{
return @"in the last 15 minutes";
}
if (timeFromNow < kHalfAnHour)
{
if(!halfHourStrings)
{
halfHourStrings = [[NSArray arrayWithObjects:@"in the last half hour",
//@"in the last half an hour",
@"in the last 30 minutes",
//@"about half an hour ago",
@"fairly recently",
nil] retain];
}
unsigned int index = random() % ([halfHourStrings count] - 1);
return [halfHourStrings objectAtIndex:index];
}
if (timeFromNow < kOneHour)
{
return @"in the last hour";
}
if ((timeFromNow < (kOneHour + kFiveMinutes)) && (timeFromNow > (kOneHour - kFiveMinutes)))
{
return @"about an hour ago";
}
if((timeFromNow < ((kOneHour*2.0f) + kFiveMinutes ))&& (timeFromNow > ((kOneHour*2.0f) - kFiveMinutes)))
{
return @"a couple of hours ago";
}
// Now we're over an hour, we need to calculate a few specific dates to compare against
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents* todayComponents = [gregorian components:unitFlags fromDate:today];
todayComponents.hour = 12;
NSDate* noonToday = [gregorian dateFromComponents:todayComponents];
NSTimeInterval timeSinceNoonToday = [self timeIntervalSinceDate:noonToday];
if (timeSinceNoonToday > 0) // sometime since noon
{
if (timeSinceNoonToday > kOneHour * 9) // i.e. after 9pm today
return @"earlier tonight";
if (timeSinceNoonToday > kOneHour * 7) // i.e. after 7pm today
return @"earlier this evening";
if (timeSinceNoonToday < kOneHour * 1) // between noon and 1pm
return @"early this afternoon";
return @"this afternoon";
}
NSTimeInterval timeSinceMidnight = kHalfADay -timeSinceNoonToday; // Note sign is reversed.
if ((timeSinceNoonToday < 0) & (timeSinceNoonToday > -kHalfADay)) // between midnight and noon today
{
if (timeSinceMidnight < kFiveMinutes)
return @"around midnight";
if (timeSinceMidnight < kOneHour * 2) // up to 2am
return @"very early this morning";
if (timeSinceMidnight < kOneHour * 5) // up to 5am
return @"early this morning";
else if (timeSinceMidnight < kOneHour * 11)
return @"late this morning";
else
return @"this morning";
}
// NSTimeInterval timeSinceNoonYesterday = timeSinceNoonToday - kOneDay;
// timeSinceMidnight = -timeSinceMidnight;
if (timeSinceMidnight < kOneHour * 24) // not the day before...
{
if (timeSinceMidnight < kFiveMinutes)
return @"around midnight";
if (timeSinceMidnight < kFifteenMinutes)
return @"just before midnight";
if (timeSinceMidnight < kOneHour * 2) // after 10pm
return @"late last night";
if (timeSinceMidnight < kOneHour * 5) // After 7
return @"yesterday evening";
else if (timeSinceMidnight < kOneHour * 7)
return @"yesterday evening"; // after 5pm
else if (timeSinceMidnight < kOneHour * 7)
return @"yesterday evening"; // after 5pm
else if (timeSinceMidnight < kOneHour * 10)
return @"yesterday afternoon"; // after 5pm
else if (timeSinceMidnight < kOneHour * 12)
return @"early yesterday afternoon"; // before 1pm
else if (timeSinceMidnight < kOneHour * 13)
return @"late yesterday morning"; // after 11m
else if (timeSinceMidnight < kOneHour * 17)
return @"yesterday morning";
else
return @"early yesterday morning";
}
NSDateFormatter* formatter = [[[NSDateFormatter alloc] init] autorelease];
int integerSeconds = timeSinceMidnight;
int integerDay = kOneDay;
int secondsIntoDay = integerSeconds % integerDay;
NSString* formatString = @"last %@";
if (timeFromNow < kOneWeek)
{
if (secondsIntoDay < kFifteenMinutes)
formatString = @"around midnight on %@";
//else if (secondsIntoDay < kFifteenMinutes)
// formatString = @"just before midnight on %@";
else if (secondsIntoDay < kOneHour * 2) // after 10pm
formatString = @"late on %@ night";
else if (secondsIntoDay < kOneHour * 5) // After 7
formatString = @"on %@ evening";
else if (secondsIntoDay < kOneHour * 10)
formatString = @"on %@ afternoon"; // after 5pm
else if (secondsIntoDay < kOneHour * 12)
formatString = @"early on %@ afternoon"; // before 1pm
else if (secondsIntoDay < kOneHour * 13)
formatString = @"late on %@ morning"; // after 11am
else if (secondsIntoDay < kOneHour * 17)
formatString = @"on %@ morning";
else if (secondsIntoDay < kOneHour * 24) // not the day before...
formatString = @"early on %@ morning";
[formatter setDateFormat:@"EEEE"]; /// EEEE is long format of day of the week see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]];
}
//formatString = @"on %@ the week before last";
/*if (secondsIntoDay < kOneHour * 2) // after 10pm
formatString = @"early on %@ the week before last";
else if (timeSinceMidnight > kOneHour * 13)
formatString = @"late on %@ the week before last"; // after 11m*/
//if (timeFromNow < kOneWeek * 2)
//{
// [formatter setDateFormat:@"EEE"]; /// EEE is short format of day of the week see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
// return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]];
//}
if (timeFromNow < kOneWeek * 2)
{
return @"the week before last";
}
NSDateComponents* myComponents = [gregorian components:unitFlags fromDate:self];
int monthsAgo = myComponents.month - todayComponents.month;
int yearsAgo = myComponents.year - todayComponents.year;
if (yearsAgo == 0)
{
if (monthsAgo == 0)
{
if(myComponents.day > 22)
return @"late this month";
if(myComponents.day < 7)
{
if(!earlyMonthStrings)
{
earlyMonthStrings = [[NSArray arrayWithObjects:@"earlier this month",
//@"at the beginning of the month",
@"early this month",
nil] retain];
}
unsigned int index = random() % ([earlyMonthStrings count] - 1);
return [earlyMonthStrings objectAtIndex:index];
}
return @"earlier this month";
}
if (monthsAgo == 1)
{
if(myComponents.day > 22)
return @"late last month";
if(myComponents.day < 7)
return @"early last month";
return @"last month";
}
formatString = @"in %@ this year";
/*if(myComponents.day > 22)
formatString = @"late in %@ this year";
if(myComponents.day < 7)
formatString = @"early in %@ this year";*/
[formatter setDateFormat:@"MMMM"]; /// MMM is longformat of month see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]];
}
if (yearsAgo == 1)
{
formatString = @"in %@ last year";
/*if(myComponents.day > 22)
formatString = @"late in %@ last year";
if(myComponents.day < 7)
formatString = @"late in %@ last year";*/
[formatter setDateFormat:@"MMM"]; /// MMM is longformat of month see: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
return [NSString stringWithFormat:formatString, [formatter stringFromDate: self]];
}
// int daysAgo = integerSeconds / integerDay;
// Nothing yet...
[formatter setDateStyle:kCFDateFormatterMediumStyle];
//[formatter setTimeStyle:kCFDateFormatterShortStyle];
return [NSString stringWithFormat:@"on %@",[formatter stringFromDate: self]];
}
else
if(timeFromNow > 0) // The future
{
AICLog(kErrorLogEntry, @"FuzzyDates: Time marked as in the future: referenced date is %@, local time is %@", self, [NSDate date]);
return @"moments ago";
}
else
return @"right now"; // this seems unlikely.
return [self description]; // should never get here.
}
lamento que haya tardado tanto en publicar esto ...
Esto se basa en el código de la fecha Bonita y Humana & amp; hilos de tiempo. Agregué el manejo para " el lunes pasado, 5 pm " ;, porque me gusta eso hace más de x días. Esto maneja el pasado y el futuro hasta siglos. Estoy interesado en el aspecto de la internacionalización, por lo que esto requiere mucho más trabajo con el tiempo. Los cálculos están en la zona horaria local.
public static class DateTimePretty
{
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 WEEK = 7 * DAY;
private const int MONTH = 30 * DAY;
private const int YEAR = 365;
const string now = "just now";
const string secondsFuture = "in {0} seconds", secondsPast = "{0} seconds ago";
const string minuteFuture = "in about a minute", minutePast = "about a minute ago";
const string minutesFuture = "in about {0} minutes", minutesPast = "about {0} minutes ago";
const string hourFuture = "in about an hour", hourPast = "about an hour ago";
const string hoursFuture = "in about {0} hours", hoursPast = "about {0} hours ago";
const string tomorrow = "tomorrow, {0}", yesterday = "yesterday, {0}";
const string nextDay = "{0}", nextWeekDay = "next {0}", lastDay = "last {0}";
//const string daysFuture = "in about {0} days", daysPast = "about {0} days ago";
const string weekFuture = "in about a week", weekPast = "about a week ago";
const string weeksFuture = "in about {0} weeks", weeksPast = "about {0} weeks ago";
const string monthFuture = "in about a month", monthPast = "about a month ago";
const string monthsFuture = "in about {0} months", monthsPast = "about {0} months ago";
const string yearFuture = "in about a year", yearPast = "about a year ago";
const string yearsFuture = "in about {0} years", yearsPast = "about {0} years ago";
const string centuryFuture = "in about a century", centuryPast = "about a century ago";
const string centuriesFuture = "in about {0} centuries", centuriesPast = "about {0} centuries ago";
/// <summary>
/// Returns a pretty version of the provided DateTime: "42 years ago", or "in 9 months".
/// </summary>
/// <param name="dateTime">DateTime in local time format, not Utc</param>
/// <returns>A pretty string</returns>
public static string GetPrettyDate(DateTime dateTime)
{
DateTime dateTimeNow = DateTime.Now;
bool isFuture = (dateTimeNow.Ticks < dateTime.Ticks);
var ts = isFuture ? new TimeSpan(dateTime.Ticks - dateTimeNow.Ticks) : new TimeSpan(dateTimeNow.Ticks - dateTime.Ticks);
double delta = ts.TotalSeconds;
if (delta < 10)
return now;
if (delta < 1 * MINUTE)
return isFuture ? string.Format(secondsFuture, ts.Seconds) : string.Format(secondsPast, ts.Seconds);
if (delta < 2 * MINUTE)
return isFuture ? minuteFuture : minutePast;
if (delta < 45 * MINUTE)
return isFuture ? string.Format(minutesFuture, ts.Minutes) : string.Format(minutesPast, ts.Minutes);
if (delta < 2 * HOUR)
return isFuture ? hourFuture : hourPast;
if (delta < 7 * DAY)
{
string shortTime = DateTimeFormatInfo.CurrentInfo.ShortTimePattern;
string shortWeekdayTime = "dddd, " + shortTime;
int dtDay = (int) dateTime.DayOfWeek;
int nowDay = (int) dateTimeNow.DayOfWeek;
if (isFuture)
{
if (dtDay == nowDay)
{
if (delta < DAY)
return string.Format(hoursFuture, ts.Hours);
else
return string.Format(nextWeekDay, dateTime.ToString(shortWeekdayTime));
}
else if (dtDay - nowDay == 1 || dtDay - nowDay == -6)
return string.Format(tomorrow, dateTime.ToString(shortTime));
else
return string.Format(nextDay, dateTime.ToString(shortWeekdayTime));
}
else
{
if (dtDay == nowDay)
{
if (delta < DAY)
return string.Format(hoursPast, ts.Hours);
else
return string.Format(lastDay, dateTime.ToString(shortWeekdayTime));
}
else if (nowDay - dtDay == 1 || nowDay - dtDay == -6)
return string.Format(yesterday, dateTime.ToString(shortTime));
else
return string.Format(lastDay, dateTime.ToString(shortWeekdayTime));
}
}
//if (delta < 7 * DAY)
// return isFuture ? string.Format(daysFuture, ts.Days) : string.Format(daysPast, ts.Days);
if (delta < 4 * WEEK)
{
int weeks = Convert.ToInt32(Math.Floor((double) ts.Days / 30));
if (weeks <= 1)
return isFuture ? weekFuture : weekPast;
else
return isFuture ? string.Format(weeksFuture, weeks) : string.Format(weeksPast, weeks);
}
if (delta < 12 * MONTH)
{
int months = Convert.ToInt32(Math.Floor((double) ts.Days / 30));
if (months <= 1)
return isFuture ? monthFuture : monthPast;
else
return isFuture ? string.Format(monthsFuture, months) : string.Format(monthsPast, months);
}
// Switch to days to avoid overflow
delta = ts.TotalDays;
if (delta < 100 * YEAR)
{
int years = Convert.ToInt32(Math.Floor((double) ts.TotalDays / 365.25));
if (years <= 1)
return isFuture ? yearFuture : yearPast;
else
return isFuture ? string.Format(yearsFuture, years) : string.Format(yearsPast, years);
}
else
{
int centuries = Convert.ToInt32(Math.Floor((double) ts.TotalDays / 365.2425));
if (centuries <= 1)
return isFuture ? centuryFuture : centuryPast;
else
return isFuture ? string.Format(centuriesFuture, centuries) : string.Format(centuriesPast, centuries);
}
}
}
No estoy seguro de por qué dices que sería una práctica de codificación horrible. Cada una de las cadenas de retorno es en realidad un subconjunto del conjunto padre, por lo que puede hacerlo con bastante elegancia en una cadena if / elseif.
if timestamp < 5sec
"A moment ago"
elseif timestamp < 5min
"Few minutes ago"
elseif timestamp < 12hr && timestamp < noon
"Today Morning"
...
elseif timestamp < 1week
"Few days ago"
elseif timestamp < 1month
"Few weeks ago"
elseif timestamp < 6month
"Few Months ago"
...
else
"Really really long time ago"
En mi experiencia, estos tipos de generadores de fecha no son " difusos " en absoluto. De hecho, son solo un montón de frases basadas en frases basadas en el tiempo. Por ejemplo, cuando menos de 30 segundos son "momentos atrás", de 360 ??a 390 días son "hace apenas un año", etc. Algunos de estos usarán la fecha prevista para calcular los nombres especiales (junio, miércoles, etc. ). Lamento haberte lanzado las ilusiones que tenías.
no hace falta decirlo (pero lo diré de todos modos) no utilice un bucle where que disminuye 365 días al año, incluso en los años del salto de 366 días (o se encontrará en las filas de los desarrolladores de Zune)
Aquí hay una versión c #:
http: // tiredblogger.wordpress.com/2008/08/21/creating-twitter-esque-relative-dates-in-c/
Sé que expresar tiempos como este se ha vuelto bastante popular últimamente, pero por favor, considera una opción para cambiar las fechas "difusas" relativas y las fechas absolutas normales.
Por ejemplo, es útil saber que se hizo un comentario hace 5 minutos, pero es menos útil decirme que el comentario A fue hace 4 horas y el comentario B fue hace 9 horas cuando son las 11 AM y prefiero saberlo el comentario A se escribió cuando alguien se despertó esta mañana y el comentario B fue escrito por alguien que se queda hasta tarde (suponiendo que yo sepa que está en mi zona horaria).
- EDITAR: al observar más de cerca su pregunta, parece haber evitado esto hasta cierto punto al referirse a la hora del día en lugar de "X ago", pero por otro lado, puede dar una impresión falsa si los usuarios se encuentran en una zona horaria diferente , desde tu " esta mañana " puede estar en el medio de la noche para el usuario relevante.
Puede ser bueno aumentar los tiempos con la hora relativa del día dependiendo de la zona horaria del otro usuario, pero eso supone que los usuarios están dispuestos a suministrarlo y que es correcto.
No estaba contento con la solución en la otra pregunta. Así que hice mi propio uso de la clase Fecha y hora. OMI, su limpiador. En mis pruebas funcionó como yo quería. Espero que esto ayude a alguien.
DateTime now = DateTime.Now;
long nowticks = now.Ticks;
long thenticks = dt.Ticks;
long diff = nowticks - thenticks;
DateTime n = new DateTime(diff);
if (n.Year > 1)
{
return n.Year.ToString() + " years ago";
}
else if (n.Month > 1)
{
return n.Month.ToString() + " months ago";
}
else if (n.Day > 1)
{
return n.Day.ToString() + " days ago";
}
else if (n.Hour > 1)
{
return n.Hour.ToString() + " hours ago";
}
else if (n.Minute > 1)
{
return n.Minute.ToString() + " minutes ago";
}
else
{
return n.Second.ToString() + " seconds ago";
}
Esto casi siempre se hace con una declaración de cambio gigante y su implementación es trivial.
Ten en cuenta lo siguiente:
- Siempre pruebe primero el intervalo de tiempo más pequeño
- No olvides mantener tus cadenas localizables.
Puede encontrar la fuente de timeago útil. La descripción del complemento es "un complemento de jQuery que facilita la actualización automática de las marcas de tiempo difusas (por ejemplo," hace 4 minutos "o" hace aproximadamente 1 día ")". & Quot;
Es esencialmente un puerto de JavaScript de la función distance_of_time_in_words
de Rail dentro de un complemento de jQuery.
Mi compañía tiene esta biblioteca .NET que hace algo de lo que quiere, que hace un análisis de fecha y hora muy flexible (incluyendo algunos formatos relativos) pero solo hace salidas no relativas.
Echa un vistazo a Chrono para obtener un analizador de fecha heurístico de Javascript.
Chrono admite la mayoría de los formatos de fecha y hora, tales como:
Today, Tomorrow, Yesterday, Last Friday, etc
17 August 2013 - 19 August 2013
This Friday from 13:00 - 16.00
5 days ago
Sat Aug 17 2013 18:40:39 GMT+0900 (JST)
2014-11-30T08:15:30-05:30