Як конвертувати NSTimeInterval (секунди) в хвилини


104

Я отримав суму, secondsяка пройшла від певної події. Він зберігається у NSTimeIntervalтипі даних.

Я хочу перетворити його в minutesі seconds.

Наприклад, у мене є "326,4" секунди, і я хочу перетворити його в наступний рядок: "5:26".

Який найкращий спосіб досягти цієї мети?

Дякую.

Відповіді:


147

псевдо-код:

minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)

90
Я думаю, що також варто згадати, що NSTimerInterval - це лише typedef для double.
Арментаж

4
Дивіться відповідь Альбарегара - це кращий спосіб зробити це (більш код, але гнучкіший, ремонтопридатний)
benvolioT

1
Однак цей код дуже дорогий. Для швидкого перетворення тривалості в секундах ця відповідь краще.
SpacyRicochet

2
Зауважте, що ця відповідь дасть вам такі речі, як 1:60. Подивіться на відповідь StratFan, яка ближче до істини. Але зніміть підлогу і круглу, і ви повинні бути домашніми.
InvulgoSoft

Відповідь Міка Маккаллума, наведена нижче, на момент написання цього коментаря, здається, найбільш оновлена ​​та зроблена способом використання нативного API.
Томаш Назаренко,

183

Короткий опис

  1. Відповідь Брайана Рамзі зручніше, якщо ви хочете конвертувати лише хвилини.
  2. Якщо ви хочете, щоб какао-API зробив це за вас і перетворив ваш NSTimeInterval не лише на хвилини, а й на дні, місяці, тиждень тощо, я думаю, що це більш загальний підхід
  3. Використовуйте метод NSCalendar:

    • (NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts

    • "Повертає, як об'єкт NSDateComponents, використовуючи вказані компоненти, різницю між двома наданими датами". З документації API.

  4. Створіть 2 NSDate, різницею яких є NSTimeInterval, який ви хочете конвертувати. (Якщо ваш NSTimeInterval походить від порівняння 2 NSDate, вам не потрібно робити цей крок, і вам навіть не потрібен NSTimeInterval).

  5. Отримайте свої пропозиції від NSDateComponents

Зразок коду

// The time interval 
NSTimeInterval theTimeInterval = 326.4;

// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];

// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:theTimeInterval sinceDate:date1]; 

// Get conversion to months, days, hours, minutes
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;

NSDateComponents *conversionInfo = [sysCalendar components:unitFlags fromDate:date1  toDate:date2  options:0];

NSLog(@"Conversion: %dmin %dhours %ddays %dmoths",[conversionInfo minute], [conversionInfo hour], [conversionInfo day], [conversionInfo month]);

[date1 release];
[date2 release];

Відомі проблеми

  • Ви занадто багато для простої конверсії, ви праві, але так працює API.
  • Моя пропозиція: якщо ви звикли керувати своїми даними про час, використовуючи NSDate та NSCalendar, API зробить важку роботу за вас.

4
Однозначно, це є багато шляхів вирішення лише для того, щоб зробити невелику конверсію, але це відчуває себе комфортно, модульно і дуже гнучко, проголосуйте за цей зразок коду @Albaregar.
Rigo Vides

2
+1 Для гарної ретельної відповіді, однак цей код є досить дорогим.
Нік Вівер

1
+1 ... один застереження. Будьте обережні, використовуючи цей стиль коду, якщо вам потрібно округлити дробові секунди. Поведінка за замовчуванням - [NSCalendar компоненти: fromDate: toDate: options:] може зіпсуватись у сценарії, коли компонент toDate на 31,5 секунди (наприклад) попереду fromDate - поверненим компонентам буде 31 поле в секундах. Існує необов'язковий параметр NSWrapCalendarComponents, але з (обмеженого) експерименту, який я робив з цим, він завершується до найближчої секунди, а не округлення вгору або вниз. Ваш пробіг може відрізнятися.
Девід Дойл

%ldякщо ви знаходитесь у 64-бітовій машині.
Anoop Vaidya

5
Люди, які знаходять це (як Нік Вівер), думають, що код виглядає так, що це буде повільно. Це не так. Я роблю додаток таймера, і я просто перевіряв версію Albaregar проти чогось у стилі Брайана Рамзі (та інших) ... і що дивно, навіть опитуючи 100 разів на секунду (що є надзвичайною надмірністю) на порівняно повільному пристрої (4S ) було менше 1% різниці у використанні процесора.
mmc

42

Все це виглядає складніше, ніж потрібно! Ось короткий і приємний спосіб перетворення часового інтервалу в години, хвилини та секунди:

NSTimeInterval timeInterval = 326.4;
long seconds = lroundf(timeInterval); // Since modulo operator (%) below needs int or long

int hour = seconds / 3600;
int mins = (seconds % 3600) / 60;
int secs = seconds % 60;

Зверніть увагу, коли ви кладете float в int, ви отримуєте підлогу () автоматично, але ви можете додати його до перших двох, якщо, якщо вам стане краще :-)


Дивовижно! Я спробував код Рамзая, хоча, здається, він вийшов за секунду.
uplearnedu.com

Вам не вистачає крапки з комою в коді, але він не дозволить мені відредагувати його, щоб виправити його.
Джеф

Я думаю, що ваш підхід найкращий - простий, виконує роботу, і «запалює» кліщі. Ідеально.
BonanzaDriver

29

Пробачте мене за те, що я діва Стек ... Я не знаю, як відповісти на відповідь Брайана Рамзі ...

Використання раунду не буде працювати для другого значення між 59,5 і 59,99999. Друге значення буде 60 за цей період. Замість цього використовувати обріз ...

 double progress;

 int minutes = floor(progress/60);
 int seconds = trunc(progress - minutes * 60);

1
Насправді просто видаліть підлогу та багажник / кругло. :)
InvulgoSoft

@StratFan Чи можете ви, будь ласка, додати відповіді на години?
Шмідт

27

Якщо ви орієнтуєтесь на iOS 8 або OS X 10.10, це просто стало набагато простіше. Новий NSDateComponentsFormatterклас дозволяє перетворити задане NSTimeIntervalз його значення за секунди в локалізований рядок, щоб показати користувача. Наприклад:

Ціль-С

NSTimeInterval interval = 326.4;

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

componentFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
componentFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropAll;

NSString *formattedString = [componentFormatter stringFromTimeInterval:interval];
NSLog(@"%@",formattedString); // 5:26

Швидкий

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

componentFormatter.unitsStyle = .Positional
componentFormatter.zeroFormattingBehavior = .DropAll

if let formattedString = componentFormatter.stringFromTimeInterval(interval) {
    print(formattedString) // 5:26
}

NSDateCompnentsFormatterтакож дозволяє, щоб цей результат був у більш тривалих формах. Більш детальну інформацію можна знайти в статті NSHipster NSFormatter . І залежно від того, з якими класами ви вже працюєте (якщо ні NSTimeInterval), може бути зручніше передати форматiру екземпляр NSDateComponentsабо два NSDateоб’єкти, що можна зробити так само за допомогою наступних методів.

Ціль-С

NSString *formattedString = [componentFormatter stringFromDate:<#(NSDate *)#> toDate:<#(NSDate *)#>];
NSString *formattedString = [componentFormatter stringFromDateComponents:<#(NSDateComponents *)#>];

Швидкий

if let formattedString = componentFormatter.stringFromDate(<#T##startDate: NSDate##NSDate#>, toDate: <#T##NSDate#>) {
    // ...
}

if let formattedString = componentFormatter.stringFromDateComponents(<#T##components: NSDateComponents##NSDateComponents#>) {
    // ...
}

Це правильний спосіб створення рядка, адекватно локалізованого
SwiftArchitect

1
Ця відповідь набагато більш "об'єктивна-С" і корисна, ніж прийнята відповідь. Вам не потрібно switchабо if elseтвердження з цим. NSDateComponentsFormatterдбає про все це. Години, хвилини, секунди друкуються без турботи.
rustyMagnet

17

Код Брайана Рамзая, де-псевдофікований:

- (NSString*)formattedStringForDuration:(NSTimeInterval)duration
{
    NSInteger minutes = floor(duration/60);
    NSInteger seconds = round(duration - minutes * 60);
    return [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
}

Це не локалізується
SwiftArchitect

7

Ось версія Swift:

func durationsBySecond(seconds s: Int) -> (days:Int,hours:Int,minutes:Int,seconds:Int) {
    return (s / (24 * 3600),(s % (24 * 3600)) / 3600, s % 3600 / 60, s % 60)
}

Можна використовувати так:

let (d,h,m,s) = durationsBySecond(seconds: duration)
println("time left: \(d) days \(h) hours \(m) minutes \(s) seconds")

6
    NSDate *timeLater = [NSDate dateWithTimeIntervalSinceNow:60*90];

    NSTimeInterval duration = [timeLater  timeIntervalSinceNow];

    NSInteger hours = floor(duration/(60*60));
    NSInteger minutes = floor((duration/60) - hours * 60);
    NSInteger seconds = floor(duration - (minutes * 60) - (hours * 60 * 60));

    NSLog(@"timeLater: %@", [dateFormatter stringFromDate:timeLater]);

    NSLog(@"time left: %d hours %d minutes  %d seconds", hours,minutes,seconds);

Виходи:

timeLater: 22:27
timeLeft: 1 hours 29 minutes  59 seconds

його справді ідеальний приклад для
приховування

5

Оскільки це по суті подвійне ...

Розділіть на 60,0 і дістаньте цілісну і дробову частину.

Невід’ємною частиною буде ціла кількість хвилин.

Помножте дробову частину ще раз на 60,0.

Результатом стануть інші секунди.


3

Пам'ятайте, що оригінальне запитання стосується виводу рядка, а не псевдокоду чи окремих компонентів рядка.

Я хочу перетворити його в такий рядок: "5:26"

Багато відповідей не містять питань інтернаціоналізації, а більшість робить математичні обчислення вручну. Все просто 20 століття ...

Не займайтеся математикою самостійно (Swift 4)

let timeInterval: TimeInterval = 326.4
let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.unitsStyle = .positional
if let formatted = dateComponentsFormatter.string(from: timeInterval) {
    print(formatted)
}

5:26


Позиція на бібліотеках

Якщо вам дуже потрібні окремі компоненти та приємно читабельний код, ознайомтесь із SwiftDate :

import SwiftDate
...
if let minutes = Int(timeInterval).seconds.in(.minute) {
    print("\(minutes)")
}

5


Кредити @mickmaccallum та @polarwar за адекватне використанняDateComponentsFormatter


0

Як я це зробив у Swift (включаючи формат рядка, щоб показати його як "01:23"):

let totalSeconds: Double = someTimeInterval
let minutes = Int(floor(totalSeconds / 60))
let seconds = Int(round(totalSeconds % 60))        
let timeString = String(format: "%02d:%02d", minutes, seconds)
NSLog(timeString)

0

Версія Swift 2

extension NSTimeInterval {
            func toMM_SS() -> String {
                let interval = self
                let componentFormatter = NSDateComponentsFormatter()

                componentFormatter.unitsStyle = .Positional
                componentFormatter.zeroFormattingBehavior = .Pad
                componentFormatter.allowedUnits = [.Minute, .Second]
                return componentFormatter.stringFromTimeInterval(interval) ?? ""
            }
        }
    let duration = 326.4.toMM_SS()
    print(duration)    //"5:26"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.