NSTimeIntervalからHH:mm:ss?


85

NSTimeIntervalが200.0に設定されている場合、それを00:03:20に変換する方法はありますか?それを使用してNSDateを初期化し、HH:mm:ssを使用してNSDateFormatterを使用できると考えていました。私の質問は、これを行う簡単な方法はあります[NSString stringWithFormat: %02d:%02d:%02d, myHour, myMin, mySec]か、それとも自分で番号を分割して使用する必要がありますか?

回答:


198

NSDateFormatter除算とモジュロ以外のものを使用する必要はありません。NSTimeInterval秒を含む単なるdoubleです。

迅速

func stringFromTimeInterval(interval: NSTimeInterval) -> String {
    let interval = Int(interval)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}

Objective-C

- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
    NSInteger ti = (NSInteger)interval;
    NSInteger seconds = ti % 60;
    NSInteger minutes = (ti / 60) % 60;
    NSInteger hours = (ti / 3600);
    return [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
}

それは私が考えていたことですが、iOSSDKの一部としてすでに含まれているものが欠落していないことを確認したかっただけです。
fuzzygoat 2011

1
「:」は英語と他のいくつかの言語でのみ区切り文字として機能することを指摘したいと思います。たとえば、フィンランド語では「。」を使用します。-この「15.02.59」のように
sgosha 2014

@sgosha、正確には、通常、Appleはこれらのフォーマッタを提供する傾向があります。代わりに、フォーマットにローカライズされた文字列を使用する必要がありますか?
Gerry Shaw

20
(他のコメントが述べているように)区切り文字をローカライズしないため、これは間違った答えです。NSDateCompomentsFormatterを使用すると、時間間隔を1行で正しくフォーマットできます。たとえばNSDateComponentsFormatter().stringFromTimeInterval(NSTimeInterval(duration))、swift
Ilias Karim

4
ローカリゼーションと将来の保証のための正しい解決策は、@ jrc
voidref

102

iOS 8では、を使用しますNSDateComponentsFormatter

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

「3:20」を出力します。

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
dateComponentsFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
dateComponentsFormatter.allowedUnits = (NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond);
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

「0:03:20」を出力します。


2
素晴らしいアップデート。しかし、それが本当にそのような単純な計算である場合、これらのオブジェクトを使用することは(動的フォーマットが含まれていない限り)大きなオーバーヘッドではないでしょうか?
Julian F. Weinert 2015

2
あなたは、文字列等のロケール異なるため、正しく表示されますことを確認するためにフォーマットする必要がある
マックス・マクラウド

本当に小さなコメントですが、ObjectiveCの質問にC関数の例を示すのは奇妙です。おそらくObjectiveC形式に変更する価値がありますか?
リラックマ2016年

たくさんのコードを節約できました!これが私がOrangeIRCに使用した方法です。
ahyattdev 2016

17

スウィフト3のバージョンonmyway133の答え:

import Foundation

func format(_ duration: TimeInterval) -> String {
    let formatter = DateComponentsFormatter()
    formatter.zeroFormattingBehavior = .pad
    formatter.allowedUnits = [.minute, .second]

    if duration >= 3600 {
        formatter.allowedUnits.insert(.hour)
    }

    return formatter.string(from: duration)!
}


print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00

DateFormatterやNumberFormatterのように、DateComponentsFormatterの作成はパフォーマンス的にコストがかかりますか?
モシェ2017

1
代わりに、時間の価値があるかどう設定し、チェックするzeroFormattingBehaviorように[.dropLeading, .pad]、より良い(より少ないコード)オプションであるかもしれません。
MaddTheSane

コメントが正しくないようです。このコードの結果:00:12、01:05、29:10、01:04:50、12:42:00
ヨルダンH

10

いくつかの余分なコード行がありますが、NSDateComponentsを使用するとより正確な値が得られると思います。

- (NSString *)getTimeRepresentationFromDate:(NSDate *)iDate withTimeInterval:(NSTimeInterval)iTimeInterval {
    NSString *aReturnValue = nil;
    NSDate *aNewDate = [iDate dateByAddingTimeInterval:iTimeInterval]; 

    unsigned int theUnits = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSCalendar *aCalender = [NSCalendar currentCalendar];
    NSDateComponents *aDateComponents = [aCalender components:theUnits fromDate:iDate toDate:aNewDate options:0];

    aReturnValue = [NSString stringWithFormat:@"%d:%d:%d", [aDateComponents hour], [aDateComponents minute], [aDateComponents second]];

    return aReturnValue;
}

上記の方法では、TimeIntervalが作成される2つの日付を使用します。[NSDatedate]をデフォルト値としてiDateパラメーターに渡すこともできます。
Roshit 2011年

2
これは、@ matthias-bauchで使用される方法よりもどのように「より正確」ですか?
jb 2013

1
この方法では、時間間隔を秒、時間、分、つまり60で取得しますが、@ matthias-bauchの回答では、10進数で表示されます。たとえば、十分な時間を待つと、2分19秒ではなく1分79秒になります。
Ashish Pisey 2014年

これは、受け入れられているソリューションよりもはるかに優れたソリューションです。「:」の使用は国際化にとって依然として問題ですが、少なくともこれはうるう日と夏時間の境界を越えて堅牢です。
evanflash 2014

@AshishPiseyモジュロ演算子の防止59よりも大きいもの
マティアスBauch

8

ではスウィフト2iOSの8+。これにより、必要な場合にのみ時間を表示するようになります

func format(duration: NSTimeInterval) -> String {
  let formatter = NSDateComponentsFormatter()
  formatter.zeroFormattingBehavior = .Pad

  if duration >= 3600 {
    formatter.allowedUnits = [.Hour, .Minute, .Second]
  } else {
    formatter.allowedUnits = [.Minute, .Second]
  }

  return formatter.stringFromTimeInterval(duration) ?? ""
}

だからあなたは持っています

print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00

4
NSTimeInterval ti = 3667;
double hours = floor(ti / 60 / 60);
double minutes = floor((ti - (hours * 60 * 60)) / 60);
double seconds = floor(ti - (hours * 60 * 60) - (minutes * 60));

4

スウィフト4

DateComponentsFormatter().string(from: <# TimeInterval #>)

例:

DateComponentsFormatter().string(from: 59.0)

3

Matthias Bauchの提案を「拡張」するために、SwiftではこれをNSTimeIntervalの計算されたプロパティにします。

extension NSTimeInterval {
  var stringValue: String {
    let interval = Int(self)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
  }
}

これの利点はNSTimeInterval、View Controllerやその他の関数を配置する場所ではなく、型にアタッチされることです。使用するには、次のようになります。

let timeInterval = NSDate().timeIntervalSinceDate(start)        
self.elapsedTimeLabel.text = timeInterval.stringValue

ありがとう、ケニー!私の場合、それらを個別に必要としたので、拡張機能に変数を追加しました: "var seconds:Int {let interval = Int(self); let seconds = interval%60; returnseconds}"など。そのため、使用法は次のようになります。print( "使用分:(timeInterval.minutes)")
Vitalii

3

@ onmyway133の回答に基づいて、Swift4バージョンを次に示します。

func format(duration: TimeInterval) -> String {
    let formatter = DateComponentsFormatter()
    formatter.zeroFormattingBehavior = .pad

    if duration >= 3600 {
        formatter.allowedUnits = [.hour, .minute, .second];
    } else {
        formatter.allowedUnits = [.minute, .second];
    }

    return formatter.string(from: duration) ?? "";
}

0

アップルのドキュメントから直接:hファイル内:

 @property(strong,nonatomic)NSDateComponentsFormatter *timerFormatter;

mファイルで

@synthesize timerFormatter;

- (void)viewDidLoad {
[super viewDidLoad];
NSDateComponentsFormatter *timerFormatter = [[NSDateComponentsFormatter alloc] init];
timerFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional; 
//10:59 Positional THIS ONE DOES NOT SEEM TO WORK iOS<9 WHEN <1Minute JUST SHOWS 01, 10m 59s Abbreviated, 10min 59sec Short, 10minutes 59seconds Full ...
timerFormatter.allowedUnits = NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
}

NSTimeInterval timeIntervalをhh:mm:ss文字列に変換する必要がある場合は、次のようにします。

NSString *txt=[timerFormatter stringFromTimeInterval:timeInterval];

0

私は、タイマーの端数を排除する必要があると思います。Matthiasのコードが数秒でその問題を作成していたので、Matthiasのコードから少し変更した次のものを使用します

    - (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
        int ti = (int) ceil(interval);
        int seconds = ti % 60;
        int minutes = (ti / 60) % 60;
        int hours = (ti / 3600);
        return [NSString stringWithFormat:@"%02d:%02d:%02d",hours, minutes, seconds];
    }

0

onmyway133の回答のObjectiveCバージョン

- (NSString*) formatTimeInterval:(NSTimeInterval) timeInterval {

    NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];

    formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;

    if (timeInterval > 3600) {
        formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    } else {
        formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
    }

    return [formatter stringFromTimeInterval:timeInterval];
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.