NSTimeInterval в HH: mm: ss?

85

Если у меня есть NSTimeInterval, для которого установлено значение 200.0, есть ли способ преобразовать его в 00:03:20, я подумал, что могу инициализировать NSDate с ним, а затем использовать NSDateFormatter, используя HH: mm: ss. У меня вопрос: есть ли быстрый способ сделать это или мне нужно самому разбить номер и использовать [NSString stringWithFormat: %02d:%02d:%02d, myHour, myMin, mySec]?

пушистая коза
источник

Ответы:

198

Не нужно использовать NSDateFormatterничего, кроме деления и по модулю. NSTimeIntervalэто просто двойник, содержащий секунды.

Swift

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)
}

Цель-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];
}
Маттиас Баух
источник
Я очень признателен, это то, о чем я думал, но я просто хотел убедиться, что мне не хватает чего-то, что уже включено в iOS SDK.
fuzzygoat
1
Хочу отметить, что ":" работает как разделитель только на английском и некоторых других языках. В финском, например, используется "." - вот так "15.02.59"
сгоша
@sgosha, как правило, Apple обычно предоставляет для них средства форматирования. Должен ли я вместо этого использовать локализованную строку для форматирования?
Джерри Шоу
20
это неправильный ответ, поскольку он не локализует разделитель (как упоминается в других комментариях). используя NSDateCompomentsFormatter, вы можете правильно отформатировать свой временной интервал в одной строке, например, NSDateComponentsFormatter().stringFromTimeInterval(NSTimeInterval(duration))в быстром
Ilias Karim
4
Для локализации и будущей проверки правильным решением является использование NSDateComponentsFormatter, как описано @jrc
voidref 02
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».

jrc
источник
2
Хорошее обновление. Но если это действительно такой простой расчет, не приведет ли использование этого объекта к огромным накладным расходам (если не используется динамический формат)?
Джулиан Ф. Вайнерт,
2
вам нужно форматирование, чтобы строка отображалась правильно для разных языков и т. д.
Макс МакЛауд,
Действительно крошечный комментарий, но странно приводить пример функции C для вопроса ObjectiveC. Наверное, стоит поменять его на формат ObjectiveC?
Rilakkuma
Сэкономил мне тонну кода! Вот как я его использовал для OrangeIRC .
ahyattdev
17

Swift 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
Скотт Гарднер
источник
Является ли создание DateComponentsFormatter дорогостоящим с точки зрения производительности, например DateFormatter или NumberFormatter?
Моше
1
Вместо того , чтобы проверить , если есть час значение, полагая zeroFormattingBehavior, что [.dropLeading, .pad]может быть лучшим вариантом (меньше кода).
MaddTheSane
Комментарии кажутся неверными. Этот код дает следующие результаты: 00:12, 01:05, 29:10, 01:04:50, 12:42:00
Jordan 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;
}
Рошит
источник
Вышеупомянутый метод использует 2 даты, с помощью которых создается TimeInterval. Вы также можете передать [NSDate date] параметру iDate в качестве значения по умолчанию.
Рошит
2
В каком смысле этот метод «более точен», чем метод, используемый @ matthias-bauch?
jb
1
с помощью этого метода вы получаете временной интервал в секундах, часах, минутах, то есть с точки зрения 60, в то время как ответ @ matthias-bauch дает вам в десятичном выражении, например, если вы подождете достаточное время, вы увидите 1 минуту 79 секунд вместо 2 минут 19 секунд
Ашиш Писей
Это намного лучшее решение, чем принятое решение. Использование «:» по-прежнему является проблемой для интернационализации, но, по крайней мере, это надежно в високосные дни и границы перехода на летнее время.
evanflash
@AshishPisey Оператор по модулю предотвращает все, что больше 59.
Маттиас Баух,
8

В Swift 2 , IOS , 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
onmyway133
источник
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

Swift 4

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

пример:

DateComponentsFormatter().string(from: 59.0)
Якуб
источник
3

Чтобы «расширить» предложение Маттиаса Бауха, в 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типу, а не к вашему контроллеру представления или где еще вы поместили эту функцию. Чтобы использовать, вы должны пойти примерно так:

let timeInterval = NSDate().timeIntervalSinceDate(start)        
self.elapsedTimeLabel.text = timeInterval.stringValue
Кенни Винкер
источник
Спасибо, Кенни! В моем случае они мне понадобились отдельно, поэтому я добавил в ваше расширение дополнительные переменные: «var seconds: Int {let interval = Int (self); let seconds = interval% 60; return seconds}» и так далее для минут и часов. Таким образом, использование будет следующим: print ("потраченные минуты: (timeInterval.minutes)")
Виталий
3

Основываясь на ответе @ onmyway133, вот версия Swift 4:

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

прямо из документации Apple: в файле h:

 @property(strong,nonatomic)NSDateComponentsFormatter *timerFormatter;

в м файле

@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

Я полагаю, что дробь таймера должна быть отключена. Поскольку код Матиаса создавал эту проблему за секунды, я использую следующее, немного измененное по сравнению с кодом Матиаса

    - (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

Objective C версия ответа onmyway133

- (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];
}
Fonix
источник