まいまいワークス

主にiPhoneアプリの開発で考えた事、調べた事、感じた事などを記していきます。

意外と面倒!タイムラインで見られる1時間前、1日前といった文字列を生成する

関連記事  NSDateの罠 - まいまいワークス

サーバーから取得した時間情報を元に、現在の時刻から計算を行い、タイムラインで見られる1時間前、1日前といった文字列を生成します。
サーバーが日本時間を基準に値を返し、iPhoneで設定された時間帯がアメリカだったりすると時差の関係で表示がおかしくなったりしますが、ここも考慮していきます。
日付関連はハマりポイントが多いです!

ソースは以下の通り
サーバーが2014-04-25 12:34:56という値を返したと想定します。

    //サーバーがこの値を返したと仮定
    NSString* dateStr = @"2014-04-25 12:34:56";
    
    //時差補正用数値の指定
    float diff = [[NSTimeZone localTimeZone] secondsFromGMT];   //時差補正用
    float diffTokyoTimeZone = 9*60*60;  //サーバーがGMTの時間を送ってきていればここは0になる
    
    //フォーマット指定
    NSDateFormatter* format = [NSDateFormatter new];
    [format setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    //これで端末の設定に関わらずデータを取得する。
    [format setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
    
    //ロケーションに関わらずその瞬間のGMTを取得
    NSDate* now = [NSDate date];

    //sinceDate以降はロケーションによって値が時差分補正されたGMTになる (datestrは不変)
    //dateWithTimeInterval以降のオフセットはdiffとdiffTokyoTimeZoneで指定。
    //diff:GMTからの時差(秒)で補正。sinceDate以降の値の補正を相殺→ロケーションに関わらず一定のNSDate値を使用できる
    //diffTokyoTimeZone:stringで得られる時刻がJSTで得られる前提でロケーションに関わらず9時間戻す
    NSDate* date = [NSDate dateWithTimeInterval:diff-diffTokyoTimeZone sinceDate:[format dateFromString:datestr]];
    
    
    //経過時間の計算
    NSCalendar* cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents* comps = [NSDateComponents new];
    
    //秒を計算
    comps = [cal components:NSSecondCalendarUnit fromDate:date toDate:now options:0];
    NSUInteger sec = [comps second];
    
    //分を計算
    comps = [cal components:NSMinuteCalendarUnit fromDate:date toDate:now options:0];
    NSUInteger min = [comps minute];
    
    //時間を計算
    comps = [cal components:NSHourCalendarUnit fromDate:date toDate:now options:0];
    NSUInteger hour = [comps hour];
    
    //日数を計算
    comps = [cal components:NSDayCalendarUnit fromDate:date toDate:now options:0];
    NSUInteger day = [comps day];
    
    //週を計算
    comps = [cal components:NSWeekCalendarUnit fromDate:date toDate:now options:0];
    NSUInteger week = [comps week];
    
    //月を計算
    comps = [cal components:NSMonthCalendarUnit fromDate:date toDate:now options:0];
    NSUInteger month = [comps month];
    
    //年を計算
    comps = [cal components:NSYearCalendarUnit fromDate:date toDate:now options:0];
    NSUInteger year = [comps year];

sec,min,hour,day,week,month,yearにそれぞれの単位で計算された差分が入ります。
あとはこれを煮るなり焼くなりなのですが、今回は以下のようにしてみます。
差分が30秒未満ならたった今それ以外なら単純に〜時間前といった値を生成します。

    NSString* outStr;
    if (year != 0) {
        outStr = [NSString stringWithFormat:@"%ld年前",year];
    }else if (month != 0) {
        outStr = [NSString stringWithFormat:@"%ldヶ月前",month];
    }else if (week != 0){
        outStr = [NSString stringWithFormat:@"%ld週間前",week];
    }else if (day != 0){
        outStr = [NSString stringWithFormat:@"%ld日前",day];
    }else if (hour != 0){
        outStr = [NSString stringWithFormat:@"%ld時間前",hour];
    }else if (min != 0){
        outStr = [NSString stringWithFormat:@"%ld分前",min];
    }else if (sec != 0){
        if (sec < 30) {
            outStr = @"たった今";
        }else{
            outStr = [NSString stringWithFormat:@"%ld秒前",sec];
        }
    }else{
        outStr = @"error";
    }