Cara mengonversi NSTimeInterval (detik) menjadi menit

104

Saya mendapat jumlah secondsyang lulus dari acara tertentu. Ini disimpan dalam NSTimeIntervaltipe data.

Saya ingin mengubahnya menjadi minutesdan seconds.

Misalnya saya punya: "326.4" detik dan saya ingin mengubahnya menjadi string berikut: "5:26".

Apa cara terbaik untuk mencapai tujuan ini?

Terima kasih.

Ilya Suzdalnitski
sumber

Jawaban:

147

pseudo-code:

minutes = floor(326.4/60)
seconds = round(326.4 - minutes * 60)
Brian Ramsay
sumber
90
Saya rasa perlu juga disebutkan bahwa NSTimerInterval hanyalah typedef untuk double.
Armentage
4
Lihat jawaban Albaregar - ini adalah cara yang lebih baik untuk melakukan ini (lebih banyak kode tetapi lebih fleksibel, dapat dipelihara)
benvolioT
1
Namun, kode itu sangat mahal. Untuk konversi cepat berdurasi dalam hitungan detik, jawaban ini lebih baik.
SpacyRicochet
2
Harap dicatat bahwa jawaban ini akan memberi Anda hal-hal seperti 1:60. Lihatlah jawaban StratFan yang lebih mendekati kebenaran. Tapi hapus lantai dan putaran dan Anda harus bebas di rumah.
InvulgoSoft
Jawaban Mick MacCallum di bawah ini pada saat menulis komentar ini tampaknya paling diperbarui dan dibuat dengan cara menggunakan API asli.
Tomasz Nazarenko
183

Deskripsi singkat

  1. Jawaban dari Brian Ramsay lebih mudah jika Anda hanya ingin mengonversi ke menit.
  2. Jika Anda ingin Cocoa API melakukannya untuk Anda dan mengubah NSTimeInterval Anda tidak hanya menjadi menit tetapi juga menjadi hari, bulan, minggu, dll, ... Saya pikir ini adalah pendekatan yang lebih umum
  3. Gunakan metode NSCalendar:

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

    • "Pengembalian, sebagai objek NSDateComponents menggunakan komponen tertentu, perbedaan antara dua tanggal yang disediakan". Dari dokumentasi API.

  4. Buat 2 NSDate yang perbedaannya adalah NSTimeInterval yang ingin Anda ubah. (Jika NSTimeInterval Anda berasal dari membandingkan 2 NSDate, Anda tidak perlu melakukan langkah ini, dan Anda bahkan tidak memerlukan NSTimeInterval).

  5. Dapatkan kutipan Anda dari NSDateComponents

Kode sampel

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

Masalah Dikenal

  • Terlalu banyak untuk konversi saja, Anda benar, tapi begitulah cara kerja API.
  • Saran saya: jika Anda terbiasa mengatur data waktu menggunakan NSDate dan NSCalendar, API akan bekerja keras untuk Anda.
Albaregar
sumber
4
Jelas ada banyak solusi hanya untuk melakukan sedikit konversi, tetapi rasanya nyaman, modular, dan sangat fleksibel, pilih kode sampel ini @Albaregar.
Rigo Vides
2
+1 Untuk jawaban menyeluruh yang bagus, namun kode ini cukup mahal.
Nick Weaver
1
+1 ... satu peringatan. Hati-hati menggunakan gaya kode ini jika Anda perlu membulatkan pecahan detik. Perilaku default - [NSCalendar components: fromDate: toDate: options:] dapat mengacaukan skenario di mana komponen toDate adalah 31,5 detik (misalnya) sebelum fromDate - komponen yang dikembalikan akan memiliki 31 di bidang detik. Ada parameter opsional NSWrapCalendarComponents, tetapi dari eksperimen (terbatas) yang saya lakukan dengan ini, ini membungkus ke detik terdekat daripada membulatkan ke atas atau ke bawah. Jarak tempuh Anda mungkin berbeda.
David Doyle
%ldjika Anda berada di mesin 64 bit.
Anoop Vaidya
5
Orang-orang yang menemukan ini (seperti Nick Weaver) akan berpikir bahwa kodenya terlihat lambat. Tidak. Saya membuat aplikasi pengatur waktu dan saya baru saja menguji versi Albaregar terhadap sesuatu dalam gaya Brian Ramsey (dan lainnya) ... dan yang mengejutkan, bahkan melakukan polling 100 kali per detik (yang sangat berlebihan) pada perangkat yang relatif lambat (4S) ) terdapat perbedaan kurang dari 1% dalam penggunaan prosesor.
mmc
42

Semua ini terlihat lebih rumit dari yang seharusnya! Berikut adalah cara singkat dan manis untuk mengubah interval waktu menjadi jam, menit, dan detik:

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;

Perhatikan ketika Anda meletakkan float ke dalam int, Anda mendapatkan floor () secara otomatis, tetapi Anda dapat menambahkannya ke dua yang pertama jika membuat Anda merasa lebih baik :-)

Prasad
sumber
Hebat! Saya mencoba kode Ramsay meskipun tampaknya keluar sedetik.
uplearnedu.com
Anda kehilangan titik koma dalam kode Anda, tetapi saya tidak dapat mengeditnya untuk memperbaikinya.
ampun
Saya pikir pendekatan Anda adalah yang terbaik - sederhana, menyelesaikan pekerjaan, dan "ringan". Sempurna.
BonanzaDriver
29

Maafkan saya karena saya masih perawan Stack ... Saya tidak yakin bagaimana membalas jawaban Brian Ramsay ...

Penggunaan round tidak akan berhasil untuk nilai kedua antara 59.5 dan 59.99999. Nilai kedua akan menjadi 60 selama periode ini. Gunakan trunc sebagai gantinya ...

 double progress;

 int minutes = floor(progress/60);
 int seconds = trunc(progress - minutes * 60);
StratFan
sumber
1
Sebenarnya hanya membuang lantai dan batang / bulatnya sama sekali. :)
InvulgoSoft
@StratFan Bisakah Anda menambahkan jam buka ke jawaban Anda?
Shmidt
27

Jika Anda menargetkan pada atau di atas iOS 8 atau OS X 10.10, ini menjadi jauh lebih mudah. Kelas baru NSDateComponentsFormattermemungkinkan Anda mengonversi yang diberikan NSTimeIntervaldari nilainya dalam hitungan detik menjadi string yang dilokalkan untuk ditunjukkan kepada pengguna. Sebagai contoh:

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

Cepat

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

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

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

NSDateCompnentsFormatterjuga memungkinkan keluaran ini dalam bentuk yang lebih panjang. Info lebih lanjut dapat ditemukan di artikel NSFormatter NSHipster . Dan bergantung pada kelas apa yang sudah Anda kerjakan (jika tidak NSTimeInterval), mungkin lebih mudah untuk meneruskan pemformat sebuah instance NSDateComponents, atau dua NSDateobjek, yang dapat dilakukan juga melalui metode berikut.

Objective-C

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

Cepat

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

if let formattedString = componentFormatter.stringFromDateComponents(<#T##components: NSDateComponents##NSDateComponents#>) {
    // ...
}
Mick MacCallum
sumber
Ini adalah cara yang tepat untuk membuat string, dilokalkan secara memadai
SwiftArchitect
1
Jawaban ini jauh lebih "Objective-C" dan berguna daripada jawaban yang diterima. Anda tidak perlu switchatau if elsepernyataan dengan ini. NSDateComponentsFormattermengurus semuanya. Jam, Menit, Detik dicetak tanpa khawatir.
rustyMagnet
17

Kode Brian Ramsay, de-pseudofied:

- (NSString*)formattedStringForDuration:(NSTimeInterval)duration
{
    NSInteger minutes = floor(duration/60);
    NSInteger seconds = round(duration - minutes * 60);
    return [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
}
Yang Meyer
sumber
Ini tidak melokalkan
SwiftArchitect
7

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

Bisa digunakan seperti ini:

let (d,h,m,s) = durationsBySecond(seconds: duration)
println("time left: \(d) days \(h) hours \(m) minutes \(s) seconds")
Jochen Bedersdorfer
sumber
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);

Keluaran:

timeLater: 22:27
timeLeft: 1 hours 29 minutes  59 seconds
polarware
sumber
contoh yang sangat sempurna untuk
ravinder521986
5

Karena pada dasarnya ini adalah ...

Bagilah dengan 60.0 dan ekstrak bagian integral dan bagian pecahannya.

Bagian integral adalah bilangan bulat menit.

Kalikan kembali bagian pecahannya dengan 60,0.

Hasilnya adalah detik-detik yang tersisa.


sumber
3

Ingatlah bahwa pertanyaan awal adalah tentang keluaran string, bukan pseudo-code atau komponen string individual.

Saya ingin mengubahnya menjadi string berikut: "5:26"

Banyak jawaban yang hilang dari masalah internasionalisasi, dan kebanyakan melakukan perhitungan matematika dengan tangan. Semua hanya abad ke-20 ...

Jangan lakukan Matematika sendiri (Swift 4)

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

5:26


Memanfaatkan perpustakaan

Jika Anda benar-benar menginginkan komponen individual, dan kode yang mudah dibaca, lihat SwiftDate :

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

5


Kredit ke @mickmaccallum dan @polarwar untuk penggunaan yang memadai dariDateComponentsFormatter

SwiftArchitect
sumber
0

Bagaimana saya melakukan ini di Swift (termasuk pemformatan string untuk menunjukkannya sebagai "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)
SilentDirge
sumber
0

Versi 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"
SPatel
sumber