Ответ 1
псевдокода:
minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)
У меня есть количество seconds
, прошедших с определенного события. Он хранится в NSTimeInterval
данных NSTimeInterval
.
Я хочу преобразовать это в minutes
и seconds
.
Например, у меня есть: "326,4" секунд, и я хочу преобразовать его в следующую строку: "5:26".
Как лучше всего достичь этой цели?
Благодарю.
псевдокода:
minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)
Краткое описание
Использовать метод NSCalendar:
(NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts
"Возвращает, как объект NSDateComponents с использованием указанных компонентов, разницу между двумя датами поставки". Из документации API.
Создайте 2 NSDate, чья разница в NSTimeInterval, которую вы хотите преобразовать. (Если ваш NSTimeInterval приходит от сравнения 2 NSDate, вам не нужно делать этот шаг, и вам даже не нужен NSTimeInterval).
Получите ваши кавычки из 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];
Известные проблемы
Все это выглядит сложнее, чем нужно! Вот короткий и сладкий способ преобразования временного интервала в часы, минуты и секунды:
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, вы получите floor() автоматически, но вы можете добавить его в первые два, если, если вам станет лучше: -)
Прости меня за то, что я был девственницей стека... Я не уверен, как ответить на ответ Брайана Рамсей...
Использование раунда не будет работать для вторых значений между 59.5 и 59.99999. Второе значение будет 60 в течение этого периода. Вместо этого используйте trunc...
double progress;
int minutes = floor(progress/60);
int seconds = trunc(progress - minutes * 60);
Если вы настроите таргетинг на iOS 8 или OS X 10.10 или выше, это стало намного проще. Новый класс NSDateComponentsFormatter
позволяет вам преобразовать заданный NSTimeInterval
из его значения в секундах в локализованную строку, чтобы показать пользователя. Например:
Objective-C
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
), может быть более удобно передать formatter экземпляр NSDateComponents
или два объекта NSDate
, что также можно сделать с помощью следующие методы.
Objective-C
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#>) {
// ...
}
Код Брайана Рамсейда, de-pseudofied:
- (NSString*)formattedStringForDuration:(NSTimeInterval)duration
{
NSInteger minutes = floor(duration/60);
NSInteger seconds = round(duration - minutes * 60);
return [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
}
Здесь версия 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")
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
Так как это по существу двойное...
Разделите на 60.0 и извлеките неотъемлемую часть и дробную часть.
Неотъемлемой частью будет целое число минут.
Умножьте дробную часть на 60.0 снова.
Результатом будет оставшаяся секунда.
Помните, что исходный вопрос касается вывода строки, а не псевдокода или отдельных строковых компонентов.
Я хочу преобразовать его в следующую строку: "5:26"
Многие ответы не учитывают проблемы интернационализации, и большинство из них делают математические вычисления вручную. Все как раз в 20 веке...
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
Как я это сделал в 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)
версия 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"