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це просто подвійне, що містить секунди.

Стрімкий

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];
}

З великою вдячністю, саме про це я думав, але я просто хотів перевірити, чи не пропускав я чогось, уже включеного до складу SDK для iOS.
— fuzzygoat

1
Я хочу зазначити, що ":" працює як роздільник лише англійською та деякими іншими мовами. Наприклад, фінська використовує "." - ось так "15.02.59"
— sgosha

@sgosha, власне, як правило, Apple, як правило, пропонує для них форматування. Чи слід замість цього використовувати локалізований рядок для форматування?
— Gerry Shaw

20
це неправильна відповідь, оскільки вона не локалізує роздільник (як згадують інші коментарі). за допомогою NSDateCompomentsFormatter ви можете правильно відформатувати свій інтервал часу в одному рядку, наприклад, NSDateComponentsFormatter().stringFromTimeInterval(NSTimeInterval(duration))швидко
— Ilias Karim

4
Для локалізації та майбутньої перевірки правильним рішенням буде використання NSDateComponentsFormatter, як описано @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
Приємне оновлення. Але якщо насправді це просто такий простий розрахунок, чи не було б використання цих об’єктів величезними накладними витратами (доки не задіяний динамічний формат)?
— Джуліан Ф. Вайнерт

2
вам потрібно форматування, щоб переконатися, що рядок відображається правильно для різних мов тощо.
— Макс Маклауд,

Дійсно крихітний коментар, але дивно наводити приклад функції C для питання ObjectiveC. Можливо, варто змінити його на формат ObjectiveC?
— Рілаккума,

Врятував мені тонну коду! Ось як я використовував його для 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 с
— Ashish Pisey

Це набагато краще рішення, ніж прийняте рішення. Застосування ":" все ще залишається проблемою для інтернаціоналізації, але принаймні це надійно протягом високосних днів та літнього часу.
— 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


4

Стрімкий 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 docs: у файлі 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

Думаю, частка таймера повинна бути обмежена. Оскільки код Маттіаса створював цю проблему за лічені секунди, я використовую наступне, дещо змінене від коду Матіаса

    - (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];
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.