NSTimeInterval (saniye) dakikaya nasıl dönüştürülür


104

Bunun bir miktarını secondsbelirli bir olaydan aldım . Bir NSTimeIntervalveri türünde saklanır .

Ben dönüştürmek istiyor minutesve seconds.

Örneğin: "326.4" saniyem var ve bunu şu dizeye dönüştürmek istiyorum: "5:26".

Bu hedefe ulaşmanın en iyi yolu nedir?

Teşekkürler.

Yanıtlar:


147

sözde kod:

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

90
Ayrıca bir NSTimerInterval'in sadece double için bir typedef olduğunu belirtmekte fayda var.
Armentage

4
Albaregar'ın cevabına bakın - bunu yapmanın daha iyi bir yolu (daha fazla kod ama daha esnek, bakımı yapılabilir)
benvolioT

1
Ancak bu kod çok pahalıdır. Saniyeler içinde bir sürenin hızlı dönüşümü için bu cevap daha iyidir.
SpacyRicochet

2
Lütfen bu cevabın size 1:60 gibi şeyler vereceğini unutmayın. Gerçeğe daha yakın olan StratFan'ın cevabına bakın. Ancak zemini ve yuvarlaklığı kaldırın ve evde özgür olmalısınız.
InvulgoSoft

Mick MacCallum'un bu yorumu yazarken aşağıdaki cevabı en çok güncellenmiş ve yerel API kullanılarak yapılmış gibi görünüyor.
Tomasz Nazarenko

183

Kısa açıklama

  1. Brian Ramsay'ın cevabı, yalnızca dakikalara dönüştürmek istiyorsanız daha uygundur.
  2. Cocoa API'nin sizin için yapmasını ve NSTimeInterval'ınızı yalnızca dakikalara değil, aynı zamanda günlere, aylara, haftalara vb. Dönüştürmesini istiyorsanız ... Bunun daha genel bir yaklaşım olduğunu düşünüyorum.
  3. NSCalendar yöntemini kullanın:

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

    • "Belirtilen bileşenleri kullanan bir NSDateComponents nesnesi olarak, sağlanan iki tarih arasındaki farkı döndürür". API belgelerinden.

  4. Farkı dönüştürmek istediğiniz NSTimeInterval olan 2 NSDate oluşturun. (NSTimeInterval'iniz 2 NSDate'i karşılaştırmaktan geliyorsa, bu adımı yapmanız gerekmez ve NSTimeInterval'e bile ihtiyacınız yoktur).

  5. NSDateComponents'tan tekliflerinizi alın

Basit kod

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

Bilinen Sorunlar

  • Sadece bir dönüşüm için çok fazla, haklısınız, ancak API böyle çalışır.
  • Önerim: NSDate ve NSCalendar kullanarak zaman verilerinizi yönetmeye alışırsanız, API sizin için zor işi yapacaktır.

4
Kesinlikle biraz dönüşüm yapmak için çok fazla geçici çözüm var, ancak rahat, modüler ve gerçekten esnek geliyor, bu örnek kod için oy verin @Albaregar.
Rigo Vides

2
+1 İyi ve kapsamlı bir cevap için, ancak bu kod oldukça pahalıdır.
Nick Weaver

1
+1 ... bir uyarı. Kesirli saniyeleri yuvarlamanız gerekiyorsa bu tarz kodu kullanırken dikkatli olun. - [NSCalendar bileşenleri: fromDate: toDate: options:] öğesinin varsayılan davranışı, toDate bileşeninin fromDate tarihinden 31,5 saniye (örneğin) ileride olduğu senaryoda karışabilir - döndürülen bileşenlerin saniye alanında 31 olacaktır. NSWrapCalendarComponents'ın isteğe bağlı bir parametresi var, ancak bununla yaptığım (sınırlı) deneyime göre, yukarı veya aşağı yuvarlamak yerine en yakın saniyeye kaydırılıyor. Kilometreniz değişebilir.
David Doyle

%ld64 bit makinedeyseniz.
Anoop Vaidya

5
Bunu bulan insanlar (Nick Weaver gibi) kodun yavaş olacağını düşünecekler. Değil. Bir zamanlayıcı uygulaması yapıyorum ve Albaregar'ın sürümünü Brian Ramsey (ve diğerleri) tarzında bir şeye karşı test ettim ... ve şaşırtıcı bir şekilde, nispeten yavaş bir cihazda (4S) saniyede 100 kez (muazzam bir aşırı öldürme) ) işlemci kullanımında% 1'den az bir fark vardı.
mmc

42

Bunların hepsi olması gerekenden daha karmaşık görünüyor! İşte bir zaman aralığını saatlere, dakikalara ve saniyelere dönüştürmenin kısa ve tatlı bir yolu:

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;

Bir int'e float koyduğunuzda, otomatik olarak floor () elde edeceğinizi, ancak kendinizi daha iyi hissettirecekse ilk ikisine ekleyebilirsiniz :-)


Harika! Ramsay'in kodunu denedim ama bir saniye sonra çıkmış gibi görünüyor.
uplearnedu.com

Kodunuzda bir noktalı virgül eksik, ancak düzeltmek için düzenlememe izin vermiyor.
Jeef

Yaklaşımınızın en iyisi olduğunu düşünüyorum - basit, işi hallediyor ve tıkanıklıkları "hafifletiyor". Mükemmel.
BonanzaDriver

29

Yığın bakiresi olduğum için beni bağışlayın ... Brian Ramsay'ın cevabına nasıl cevap vereceğimi bilmiyorum ...

Round kullanmak 59.5 ile 59.99999 arasındaki ikinci değerler için çalışmayacaktır. Bu dönemde ikinci değer 60 olacaktır. Bunun yerine kısaltmayı kullanın ...

 double progress;

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

1
Aslında zemini ve gövdeyi / daireyi tamamen kaldırın. :)
InvulgoSoft

@StratFan Cevabınıza saat ekleyebilir misiniz?
Shmidt

27

İOS 8 veya OS X 10.10'u veya üzerini hedefliyorsanız, bu çok daha kolay hale geldi. Yeni NSDateComponentsFormattersınıf NSTimeInterval, kullanıcıya göstermek için belirli bir değeri saniye cinsinden yerelleştirilmiş bir dizeye dönüştürmenize olanak tanır . Örneğin:

Amaç-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

Swift

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

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

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

NSDateCompnentsFormatterayrıca bu çıktının daha uzun formlarda olmasına izin verir. NSHipster'ın NSFormatter makalesinde daha fazla bilgi bulunabilir . Ve halihazırda hangi sınıflarla çalıştığınıza bağlı olarak (değilse NSTimeInterval), biçimlendiriciye bir NSDateComponentsveya iki NSDatenesnenin bir örneğini iletmek daha uygun olabilir , bu da aşağıdaki yöntemlerle de yapılabilir.

Amaç-C

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

Swift

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

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

Bu, yeterince yerelleştirilmiş dizeyi oluşturmanın uygun yoludur
SwiftArchitect

1
Bu cevap çok daha "Amaç-C" dir ve kabul edilen cevaptan daha faydalıdır. Buna gerek yok switchya if elsebu içindeki ifadeler. NSDateComponentsFormatterhepsini halleder. Herhangi bir endişe duymadan yazdırılan Saatler, Dakikalar, Saniyeler.
rustyMagnet

17

Brian Ramsay'ın kodu, sahte:

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

Bu yerelleştirilmiyor
SwiftArchitect

7

İşte bir Swift versiyonu:

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

Bunun gibi kullanılabilir:

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

Çıktılar:

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

bir tarihi gizlemek için gerçekten mükemmel bir örnek
ravinder521986

5

Aslında bir duble olduğu için ...

60.0'a bölün ve integral kısmı ve kesirli kısmı çıkarın.

Ayrılmaz kısım tam sayı olacaktır.

Kesirli kısmı tekrar 60.0 ile çarpın.

Sonuç, kalan saniye olacaktır.


3

Orijinal sorunun sözde kod veya tek tek dizgi bileşenleri değil, bir dize çıktısı hakkında olduğunu unutmayın.

Bunu şu dizeye dönüştürmek istiyorum: "5:26"

Cevapların çoğu uluslararasılaşma sorunlarını kaçırıyor ve çoğu matematik hesaplamalarını elle yapıyor. Hepsi de 20. yüzyıl ...

Matematiği kendiniz yapmayın (Swift 4)

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

5:26


Kütüphanelerden yararlanın

Gerçekten bireysel bileşenler ve hoş bir şekilde okunabilir kod istiyorsanız, SwiftDate'e göz atın :

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

5


Yeterli kullanım için @ mickmaccallum ve @polarwar kredileriDateComponentsFormatter


0

Bunu Swift'de nasıl yaptım ("01:23" olarak göstermek için dize biçimlendirmesi dahil):

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 versiyonu

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"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.