Алгоритм нечеткой даты в Objective-C

Я хотел бы написать метод нечеткой даты для вычисления дат в Objective-C для iPhone. Здесь есть популярное объяснение:

Рассчитать относительное время в C #

Однако он содержит недостающие аргументы. Как это можно использовать в Objective-C? Благодарю.

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

Ответы на вопрос(4)

тики календаря, полагаясь на компоненты календаря, которые вы можете извлечь из разницы между двумя датами:

NSDate *nowDate =    [[NSDate alloc] init];
NSDate *targetDate = nil; // some other date here of your choosing, obviously nil isn't going to get you very far

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger unitFlags = NSMonthCalendarUnit | NSWeekCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
NSDateComponents *components = [gregorian components:unitFlags
                                            fromDate:dateTime
                                              toDate:nowDate options:0];
NSInteger months = [components month];
NSInteger weeks = [components week];
NSInteger days = [components day];
NSInteger hours = [components hour];
NSInteger minutes = [components minute];

Ключ - это установка флагов единиц измерения - это позволяет вам указать, в каких единицах времени вы хотите разбить дату / время. Если вам просто нужны часы, вы должны установить NSHourCalendarUnit, и это значение будет только увеличиваться по мере того, как ваши даты будут расходиться, потому что нет больше единицы, чтобы начать увеличиваться.

Как только у вас есть ваши компоненты, вы можете приступить к выбранной логике, возможно, изменив условный поток @ alex.

Это то, что я бросил вместе:

if (months > 1) {
    // Simple date/time
    if (weeks >3) {
        // Almost another month - fuzzy
        months++;
    }
    return [NSString stringWithFormat:@"%ld months ago", (long)months];
}
else if (months == 1) {
    if (weeks > 3) {
        months++;
        // Almost 2 months
        return [NSString stringWithFormat:@"%ld months ago", (long)months];
    }
    // approx 1 month
    return [NSString stringWithFormat:@"1 month ago"];
}
// Weeks
else if (weeks > 1) {
    if (days > 6) {
        // Almost another month - fuzzy
        weeks++;
    }
    return [NSString stringWithFormat:@"%ld weeks ago", (long)weeks];
}
else if (weeks == 1 ||
         days > 6) {
    if (days > 6) {
        weeks++;
        // Almost 2 weeks
        return [NSString stringWithFormat:@"%ld weeks ago", (long)weeks];
    }
    return [NSString stringWithFormat:@"1 week ago"];
}
// Days
else if (days > 1) {
    if (hours > 20) {
        days++;
    }
    return [NSString stringWithFormat:@"%ld days ago", (long)days];
}
else if (days == 1) {
    if (hours > 20) {
        days++;
        return [NSString stringWithFormat:@"%ld days ago", (long)days];
    }
    return [NSString stringWithFormat:@"1 day ago"];
}
// Hours
else if (hours > 1) {
    if (minutes > 50) {
        hours++;
    }
    return [NSString stringWithFormat:@"%ld hours ago", (long)hours];
}
else if (hours == 1) {
    if (minutes > 50) {
        hours++;
        return [NSString stringWithFormat:@"%ld hours ago", (long)hours];
    }
    return [NSString stringWithFormat:@"1 hour ago"];
}
// Minutes
else if (minutes > 1) {
    return [NSString stringWithFormat:@"%ld minutes ago", (long)minutes];
}
else if (minutes == 1) {
    return [NSString stringWithFormat:@"1 minute ago"];
}
else if (minutes < 1) {
    return [NSString stringWithFormat:@"Just now"];
}

NSDate объекты с помощьюtimeIntervalSinceDate: метод. Это даст вам дельту в считанные секунды.

Из этого вы можете вычислить минуты / часы / дни / месяцы / годы, разделив их на соответствующую сумму.

Решение Вопроса

NSDate учебный класс. В @ реализован удобный метNSDate чтобы получить дельту в секундах между двумя экземплярами даты,timeIntervalSinceDate:. Это называетсяNSDate Например, еще одинNSDate объект в качестве аргумента. ВозвращаетNSTimeInterval (который является typedef для двойного), который представляет количество секунд между двумя датами.

Учитывая это, было бы довольно просто адаптировать код, который вы дали выше, к контексту Objective-C / Cocoa. Поскольку дельта рассчитывается какNSDate дается в секундах, учитывая две даты, вы можете легко адаптировать приведенный выше код:

//Constants
#define SECOND 1
#define MINUTE (60 * SECOND)
#define HOUR (60 * MINUTE)
#define DAY (24 * HOUR)
#define MONTH (30 * DAY)

- (NSString*)timeIntervalWithStartDate:(NSDate*)d1 withEndDate:(NSDate*)d2
{
    //Calculate the delta in seconds between the two dates
    NSTimeInterval delta = [d2 timeIntervalSinceDate:d1];

    if (delta < 1 * MINUTE)
    {
        return delta == 1 ? @"one second ago" : [NSString stringWithFormat:@"%d seconds ago", (int)delta];
    }
    if (delta < 2 * MINUTE)
    {
        return @"a minute ago";
    }
    if (delta < 45 * MINUTE)
    {
        int minutes = floor((double)delta/MINUTE);
        return [NSString stringWithFormat:@"%d minutes ago", minutes];
    }
    if (delta < 90 * MINUTE)
    {
        return @"an hour ago";
    }
    if (delta < 24 * HOUR)
    {
        int hours = floor((double)delta/HOUR);
        return [NSString stringWithFormat:@"%d hours ago", hours];
    }
    if (delta < 48 * HOUR)
    {
        return @"yesterday";
    }
    if (delta < 30 * DAY)
    {
        int days = floor((double)delta/DAY);
        return [NSString stringWithFormat:@"%d days ago", days];
    }
    if (delta < 12 * MONTH)
    {
        int months = floor((double)delta/MONTH);
        return months <= 1 ? @"one month ago" : [NSString stringWithFormat:@"%d months ago", months];
    }
    else
    {
        int years = floor((double)delta/MONTH/12.0);
        return years <= 1 ? @"one year ago" : [NSString stringWithFormat:@"%d years ago", years];
    }
}

Это будет вызвано, передавая начало и конецNSDate объекты в качестве аргументов и возвращаютNSString с интервалом времени.

 Brock Woolf28 июн. 2009 г., 01:28
Это прекрасно работает. Благодарность
 retainCount28 июн. 2009 г., 14:47
Единственная проблема с этой реализацией состоит в том, что она не делает различий между 24 часами как днем и календарным днем. то есть, если я сравниваю 11:00 PM и 2:00 AM, разница должна быть «вчера», а не «3 часа назад». Посмотрите на NSCalendar и его сопутствующий класс NSDateComponents.

Ваш ответ на вопрос