Soru iPhone: Tarih dizgisini bir göreli zaman damgasına dönüştürme


Benim gibi bir zaman damgası var.

Per, 21 Mayıs 09 19:10:09 -0700

ve '20 dakika önce' veya '3 ​​gün önce' gibi göreceli bir zaman damgasına dönüştürmek istiyorum.

Bunu iPhone için Objective-C kullanarak yapmanın en iyi yolu nedir?


38
2018-05-24 02:39


Menşei


Bu sorunun kopyası. stackoverflow.com/questions/822124/fuzzy-date-algorithm - Marc W
... bu soruyla bağlantılı olarak: stackoverflow.com/questions/11 (evet, soru # 11) - Dave DeLong
Bu yazıyı yararlı buldum: [nstimeinterval'i dakika saniye olarak dönüştürme] [1] [1]: stackoverflow.com/questions/1189252/...
Kontrol bu cevaphangi örnek bağlantıya sahiptir. - Paresh Navadiya
Eğer zaman önce tarih formatının Facebook Mobile gibi olmasını istiyorsanız, bunu yapmak için bir süre önce yazdığım bir kütüphaneye link: github.com/nikilster/NSDate-Time-Ago - N V


Cevaplar:


-(NSString *)dateDiff:(NSString *)origDate {
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    [df setFormatterBehavior:NSDateFormatterBehavior10_4];
    [df setDateFormat:@"EEE, dd MMM yy HH:mm:ss VVVV"];
    NSDate *convertedDate = [df dateFromString:origDate];
    [df release];
    NSDate *todayDate = [NSDate date];
    double ti = [convertedDate timeIntervalSinceDate:todayDate];
    ti = ti * -1;
    if(ti < 1) {
        return @"never";
    } else  if (ti < 60) {
        return @"less than a minute ago";
    } else if (ti < 3600) {
        int diff = round(ti / 60);
        return [NSString stringWithFormat:@"%d minutes ago", diff];
    } else if (ti < 86400) {
        int diff = round(ti / 60 / 60);
        return[NSString stringWithFormat:@"%d hours ago", diff];
    } else if (ti < 2629743) {
        int diff = round(ti / 60 / 60 / 24);
        return[NSString stringWithFormat:@"%d days ago", diff];
    } else {
        return @"never";
    }   
}

71
2018-05-31 14:34



Uluslararasılaşmayı idare edemez. Apple'ın göreli saat formatını NSDateFormatter'a eklemesini isteyin. Android'de var. - an0
Uluslararasılaştırma eklemek için, sadece dizeleri NSLocalizedString () ile sarın ve çoğu durumda gitmek için iyi bir konum. - Carl Coryell-Martin
Bu NSDate üzerinde bir kategoriye sarmak için kullanışlı bir yöntem, FYI. NSDate + Relativite adlı bir tane var. Yöntemler - (NSString *) distanceOfTimeInWordsSinceDate: (NSDate *) aDate, tüm işi yapar ve kolaylık yöntemi - (NSString *) distanceOfTimeInWordsToNow, eskiden [NSDate tarih] ile çağırır - Chris Ladd
teşekkür ederim Gilean - Tuyen Nguyen
Ay ve yıl eklemek için bu kodu ekleyin: else (ti <31536000) {int diff = round (ti / 60/60/24/30); dönüş [NSString stringWithFormat: @ "% d ay önce", fark); } else {int diff = round (ti / 60/60/24/365); dönüş [NSString stringWithFormat: @ "% d yıl önce", fark); - ozba


İşte size uygun bilgileri almanıza yardımcı olacak Cocoa'dan yöntemler (hepsi koka dokunuşunda mevcut olup olmadığından emin değil).

    NSDate * today = [NSDate date];
    NSLog(@"today: %@", today);

    NSString * str = @"Thu, 21 May 09 19:10:09 -0700";
    NSDate * past = [NSDate dateWithNaturalLanguageString:str
                            locale:[[NSUserDefaults 
                            standardUserDefaults] dictionaryRepresentation]];

    NSLog(@"str: %@", str);
    NSLog(@"past: %@", past);

    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
    unsigned int unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | 
                             NSDayCalendarUnit | 
                             NSHourCalendarUnit | NSMinuteCalendarUnit | 
                             NSSecondCalendarUnit;
    NSDateComponents *components = [gregorian components:unitFlags
                                                fromDate:past
                                                  toDate:today
                                                 options:0];

    NSLog(@"months: %d", [components month]);
    NSLog(@"days: %d", [components day]);
    NSLog(@"hours: %d", [components hour]);
    NSLog(@"seconds: %d", [components second]);

NSDateComponents nesnesi, ilgili birimlerdeki (belirtildiği gibi) farkı tutar gibi görünüyor. Tüm birimleri belirtirseniz, bu yöntemi kullanabilirsiniz:

void dump(NSDateComponents * t)
{
    if ([t year]) NSLog(@"%d years ago", [t year]);
    else if ([t month]) NSLog(@"%d months ago", [t month]);
    else if ([t day]) NSLog(@"%d days ago", [t day]);
    else if ([t minute]) NSLog(@"%d minutes ago", [t minute]);
    else if ([t second]) NSLog(@"%d seconds ago", [t second]);
}

Kendinizi hesaplamak istiyorsanız, bir göz atabilirsiniz:

NSDate timeIntervalSinceDate

Ve sonra algoritmada saniyeler kullanın.

feragat: Bu arayüz kullanımdan kaldırılmışsa (kontrol etmedim), Apple'ın bunu yapmanın tercih edilen yolu NSDateFormattersAşağıdaki yorumlarda da belirtildiği gibi, oldukça güzel görünüyor - Cevabımı tarihsel nedenlerden dolayı tutacağım, kullanılan mantığa bakmak için hala yararlı olabilir.


22
2018-05-24 06:06



ahh çok şık çözüm, teşekkür ederim! - Nael El Shawwa
Not: eski NSCalendarDate / NSDateComponents yolu Mac OS X'te kullanımdan kaldırılıyor. Apple, NSDateFormatters uygulamasını yalnızca şu anda kullanmanızı öneririz. Herhangi bir bileşenle uğraşmayı oldukça kolaylaştırırlar. Ayrıca Gilean'ın cevabına bakın. - andreb
@andreb NSCalendarDate kullanımdan kaldırılıyor, ancak NSDateComponents kesinlikle değil. Bu bileşenleri bir yerden almanın doğru yolu NSDate kullanmak NSCalendar ve NSDateComponents, bu cevapta gösterildiği gibi. NSDateFormatters tek tek tarih bileşenleri almak için dize gösterimleri / dönüştürmek için kullanılmalıdır. - Nick Forge


Henüz düzenleme yapamıyorum, ama Gilean'ın kodunu aldım ve birkaç tweaks yaptım ve bir NSDateFormatter kategorisi yaptım.

Bir biçim dizgisini kabul eder, bu yüzden w / rasgele dizeler çalışır ve tekil olayların olması için dilbilgisel olarak doğru olması şartı ekledim.

Alkış,

Carl C-M

@interface NSDateFormatter (Extras)
+ (NSString *)dateDifferenceStringFromString:(NSString *)dateString
                                  withFormat:(NSString *)dateFormat;

@end

@implementation NSDateFormatter (Extras)

+ (NSString *)dateDifferenceStringFromString:(NSString *)dateString
                                  withFormat:(NSString *)dateFormat
{
  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
  [dateFormatter setDateFormat:dateFormat];
  NSDate *date = [dateFormatter dateFromString:dateString];
  [dateFormatter release];
  NSDate *now = [NSDate date];
  double time = [date timeIntervalSinceDate:now];
  time *= -1;
  if(time < 1) {
    return dateString;
  } else if (time < 60) {
    return @"less than a minute ago";
  } else if (time < 3600) {
    int diff = round(time / 60);
    if (diff == 1) 
      return [NSString stringWithFormat:@"1 minute ago", diff];
    return [NSString stringWithFormat:@"%d minutes ago", diff];
  } else if (time < 86400) {
    int diff = round(time / 60 / 60);
    if (diff == 1)
      return [NSString stringWithFormat:@"1 hour ago", diff];
    return [NSString stringWithFormat:@"%d hours ago", diff];
  } else if (time < 604800) {
    int diff = round(time / 60 / 60 / 24);
    if (diff == 1) 
      return [NSString stringWithFormat:@"yesterday", diff];
    if (diff == 7) 
      return [NSString stringWithFormat:@"last week", diff];
    return[NSString stringWithFormat:@"%d days ago", diff];
  } else {
    int diff = round(time / 60 / 60 / 24 / 7);
    if (diff == 1)
      return [NSString stringWithFormat:@"last week", diff];
    return [NSString stringWithFormat:@"%d weeks ago", diff];
  }   
}

@end

14
2017-08-04 04:21





Tamlığın yararına, @ Gilean'ın cevabına dayanarak, NSDate'de rayların şık tarih yardımcılarını taklit eden basit bir kategori için eksiksiz kod. Kategorilerdeki bir tazeleme için, bunlar NSDate nesneleri üzerinde çağıracağınız örnek yöntemlerdir. Yani, dün temsil eden bir NSDate varsa, [myDate distanceOfTimeInWordsToNow] => "1 gün".

Umarım yararlıdır!

@interface NSDate (NSDate_Relativity)

-(NSString *)distanceOfTimeInWordsSinceDate:(NSDate *)aDate;
-(NSString *)distanceOfTimeInWordsToNow;

@end



@implementation NSDate (NSDate_Relativity)


-(NSString *)distanceOfTimeInWordsToNow {
    return [self distanceOfTimeInWordsSinceDate:[NSDate date]];

}

-(NSString *)distanceOfTimeInWordsSinceDate:(NSDate *)aDate {
    double interval = [self timeIntervalSinceDate:aDate];

    NSString *timeUnit;
    int timeValue;

    if (interval < 0) {
        interval = interval * -1;        
    }

    if (interval< 60) {
        return @"seconds";

    } else if (interval< 3600) { // minutes

        timeValue = round(interval / 60);

        if (timeValue == 1) {
            timeUnit = @"minute";

        } else {
            timeUnit = @"minutes";

        }


    } else if (interval< 86400) {
        timeValue = round(interval / 60 / 60);

        if (timeValue == 1) {
            timeUnit = @"hour";

        } else {
            timeUnit = @"hours";
        }


    } else if (interval< 2629743) {
        int days = round(interval / 60 / 60 / 24);

        if (days < 7) {

            timeValue = days;

            if (timeValue == 1) {
                timeUnit = @"day";
            } else {
                timeUnit = @"days";
            }

        } else if (days < 30) {
            int weeks = days / 7;

            timeValue = weeks;

            if (timeValue == 1) {
                timeUnit = @"week";
            } else {
                timeUnit = @"weeks";
            }


        } else if (days < 365) {

            int months = days / 30;
            timeValue = months;

            if (timeValue == 1) {
                timeUnit = @"month";
            } else {
                timeUnit = @"months";
            }

        } else if (days < 30000) { // this is roughly 82 years. After that, we'll say 'forever'
            int years = days / 365;
            timeValue = years;

            if (timeValue == 1) {
                timeUnit = @"year";
            } else {
                timeUnit = @"years";
            }

        } else {
            return @"forever ago";
        }
    }

    return [NSString stringWithFormat:@"%d %@", timeValue, timeUnit];

}

@end

8
2018-06-28 15:36



Ah, ayrıca: Bu uygulamada 'daha önce' bunu daha kullanışlı hale getirmek için bıraktım. Yani bunu diyebilirsin ve @ "son itirafından beri% @ oldu.", [ConfessionDate distanceOfTimeInWordsToNow] - Chris Ladd


Aynı çözüme gelen çok fazla cevap var, ama seçimlere sahip olmak zarar görmez. İşte neyle geldiğini.

- (NSString *)stringForTimeIntervalSinceCreated:(NSDate *)dateTime
{
    NSDictionary *timeScale = @{@"second":@1,
                                @"minute":@60,
                                @"hour":@3600,
                                @"day":@86400,
                                @"week":@605800,
                                @"month":@2629743,
                                @"year":@31556926};
    NSString *scale;
    int timeAgo = 0-(int)[dateTime timeIntervalSinceNow];
    if (timeAgo < 60) {
        scale = @"second";
    } else if (timeAgo < 3600) {
        scale = @"minute";
    } else if (timeAgo < 86400) {
        scale = @"hour";
    } else if (timeAgo < 605800) {
        scale = @"day";
    } else if (timeAgo < 2629743) {
        scale = @"week";
    } else if (timeAgo < 31556926) {
        scale = @"month";
    } else {
        scale = @"year";
    }

    timeAgo = timeAgo/[[timeScale objectForKey:scale] integerValue];
    NSString *s = @"";
    if (timeAgo > 1) {
        s = @"s";
    } 
    return [NSString stringWithFormat:@"%d %@%@ ago", timeAgo, scale, s];
}

6
2017-09-12 19:58





Carl Coryell-Martin'in kodunu aldım ve tekillerin dize biçimlendirmesiyle ilgili uyarıları olmayan daha basit bir NSDate kategorisi hazırladım ve aynı zamanda hafta önce tekil olanı da yazdım:

@interface NSDate (Extras)
- (NSString *)differenceString;
@end

@implementation NSDate (Extras)

- (NSString *)differenceString{
    NSDate* date = self;
    NSDate *now = [NSDate date];
    double time = [date timeIntervalSinceDate:now];
    time *= -1;
    if (time < 60) {
        int diff = round(time);
        if (diff == 1)
            return @"1 second ago";
        return [NSString stringWithFormat:@"%d seconds ago", diff];
    } else if (time < 3600) {
        int diff = round(time / 60);
        if (diff == 1)
            return @"1 minute ago";
        return [NSString stringWithFormat:@"%d minutes ago", diff];
    } else if (time < 86400) {
        int diff = round(time / 60 / 60);
        if (diff == 1)
            return @"1 hour ago";
        return [NSString stringWithFormat:@"%d hours ago", diff];
    } else if (time < 604800) {
        int diff = round(time / 60 / 60 / 24);
        if (diff == 1)
            return @"yesterday";
        if (diff == 7)
            return @"a week ago";
        return[NSString stringWithFormat:@"%d days ago", diff];
    } else {
        int diff = round(time / 60 / 60 / 24 / 7);
        if (diff == 1)
            return @"a week ago";
        return [NSString stringWithFormat:@"%d weeks ago", diff];
    }   
}

@end

4
2017-07-26 02:03



Tam olarak aradığım şey. - RyanG


Swift'de

Kullanımı:

let time = NSDate(timeIntervalSince1970: timestamp).timeIntervalSinceNow
let relativeTimeString = NSDate.relativeTimeInString(time)
println(relativeTimeString)

Uzantı:

extension NSDate {
    class func relativeTimeInString(value: NSTimeInterval) -> String {
        func getTimeData(value: NSTimeInterval) -> (count: Int, suffix: String) {
            let count = Int(floor(value))
            let suffix = count != 1 ? "s" : ""
            return (count: count, suffix: suffix)
        }

        let value = -value
        switch value {
            case 0...15: return "just now"

            case 0..<60:
                let timeData = getTimeData(value)
                return "\(timeData.count) second\(timeData.suffix) ago"

            case 0..<3600:
                let timeData = getTimeData(value/60)
                return "\(timeData.count) minute\(timeData.suffix) ago"

            case 0..<86400:
                let timeData = getTimeData(value/3600)
                return "\(timeData.count) hour\(timeData.suffix) ago"

            case 0..<604800:
                let timeData = getTimeData(value/86400)
                return "\(timeData.count) day\(timeData.suffix) ago"

            default:
                let timeData = getTimeData(value/604800)
                return "\(timeData.count) week\(timeData.suffix) ago"
        }
    }
}

3
2018-01-14 22:32



downvote? tartış. - dimpiax
Bence bu yöntem gayet iyi çalışıyor. Tek şey, zamana dönüştürme, bu fonksiyonun bir parçası olmamalı mıydı? - Antoine
getTimeData hakkında konuştun mu? Onu sınıf kapsamından ayırdım ve sadece işlevlerde ömür boyu verdim çünkü diğer durumlarda işe yaramaz. - dimpiax
Hayır, 'Kullanım' açıklamanızdaki hesaplamayı kastediyorum. Bu bölüm olmamalı NSDate(timeIntervalSince1970: timestamp).timeIntervalSinceNow * -1 ana fonksiyona eklenmeli relativeTimeInString Artık her zaman bu hesaplamayı yapmak zorunda kalacaksınız. - Antoine
Bağımsız durumda olduğu gibi, bu dönüşümü kapsüllemek için gereken hak. değişmiş - dimpiax


NSDate sınıfını kullanın:

timeIntervalSinceDate

aralığı saniye cinsinden döndürür.

Bunu objektif-c'de uygulamak için hızlı alıştırma:

  1. "Şimdi" zamanı al NSDate
  2. Karşılaştırmak istediğiniz NSDate’i alın
  3. TimeIntervalSinceDate kullanarak aralığı saniye cinsinden alın

Ardından bu sözde kodu uygulayın:

if (x < 60) // x seconds ago

else if( x/60 < 60) // floor(x/60) minutes ago

else if (x/(60*60) < 24) // floor(x/(60*60) hours ago

else if (x/(24*60*60) < 7) // floor(x(24*60*60) days ago

ve bunun gibi...

o zaman bir ay 30,31 veya 28 gün olup olmadığına karar vermelisiniz. Basit tut - 30'u seç.

Daha iyi bir yol olabilir, ama 2 am ve bu akla ilk gelen şey ...


1
2018-05-24 06:04