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.