วิธีการแปลง 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
Armentage

4
ดูคำตอบของ Albaregar - มันเป็นวิธีที่ดีกว่าในการทำเช่นนี้ (โค้ดมากกว่า แต่ยืดหยุ่นกว่าและดูแลรักษาได้)
benvolioT

1
อย่างไรก็ตามรหัสนั้นมีราคาแพงมาก สำหรับการแปลงระยะเวลาเป็นวินาทีอย่างรวดเร็วคำตอบนี้ดีกว่า
SpacyRicochet

2
โปรดทราบว่าคำตอบนี้จะให้ข้อมูลเช่น 1:60 ดูคำตอบของ StratFan ซึ่งใกล้เคียงกับความจริงมากขึ้น แต่ถอดพื้นและรอบและคุณควรจะอยู่บ้านฟรี
InvulgoSoft

คำตอบของ Mick MacCallum ด้านล่างในขณะที่เขียนความคิดเห็นนี้ดูเหมือนจะได้รับการอัปเดตมากที่สุดและทำโดยใช้ API ดั้งเดิม
Tomasz Nazarenko

183

คำอธิบายสั้น ๆ

  1. คำตอบจาก Brian Ramsay สะดวกกว่าหากคุณต้องการแปลงเป็นนาทีเท่านั้น
  2. หากคุณต้องการให้ Cocoa API ทำเพื่อคุณและแปลง NSTimeInterval ของคุณไม่เพียง แต่เป็นนาที แต่ยังเป็นวันเดือนสัปดาห์ ฯลฯ ... ฉันคิดว่านี่เป็นวิธีการทั่วไปมากกว่า
  3. ใช้วิธี NSCalendar:

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

    • "ส่งคืนเป็นออบเจ็กต์ NSDateComponents โดยใช้ส่วนประกอบที่ระบุความแตกต่างระหว่างวันที่ที่ให้มาสองวัน" จากเอกสาร API

  4. สร้าง NSDate 2 รายการซึ่งมีความแตกต่างคือ 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 สำหรับคำตอบที่ดี แต่รหัสนี้ค่อนข้างแพง
Nick Weaver

1
+1 ... หนึ่งข้อแม้ โปรดใช้ความระมัดระวังในการใช้รหัสลักษณะนี้หากคุณต้องการปัดเศษเสี้ยววินาที ลักษณะการทำงานเริ่มต้นของ - [NSCalendar components: fromDate: toDate: options:] อาจทำให้สับสนในสถานการณ์ที่คอมโพเนนต์ toDate ยาว 31.5 วินาที (ตัวอย่าง) ก่อนวันที่ fromDate - คอมโพเนนต์ที่ส่งคืนจะมี 31 ในฟิลด์วินาที มีพารามิเตอร์ที่เป็นทางเลือกของ NSWrapCalendarComponents แต่จากการทดลอง (จำกัด ) ที่ฉันทำกับสิ่งนี้มันจะรวมเป็นวินาทีที่ใกล้ที่สุดแทนที่จะปัดเศษขึ้นหรือลง ระยะทางของคุณอาจแตกต่างกันไป
David Doyle

%ldหากคุณอยู่ในเครื่อง 64 บิต
Anoop Vaidya

5
ผู้ที่พบสิ่งนี้ (เช่น Nick Weaver) จะคิดว่าโค้ดดูเหมือนว่าจะช้า มันไม่ใช่ ฉันกำลังทำแอพจับเวลาและฉันเพิ่งทดสอบเวอร์ชันของ Albaregar กับบางสิ่งในสไตล์ของ Brian Ramsey (และอื่น ๆ ) ... และน่าแปลกใจที่แม้จะทำโพล 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;

สังเกตว่าเมื่อคุณใส่ลูกลอยลงใน int คุณจะได้พื้น () โดยอัตโนมัติ แต่คุณสามารถเพิ่มลงในสองตัวแรกได้หากทำให้คุณรู้สึกดีขึ้น :-)


สุดยอด! ฉันลองใช้รหัสของ Ramsay แล้วแม้ว่ามันจะหมดไปในวินาทีเดียว
uplearnedu.com

คุณไม่มีเครื่องหมายอัฒภาคในโค้ดของคุณ แต่ไม่ยอมให้ฉันแก้ไขเพื่อแก้ไข
Jeef

ฉันคิดว่าแนวทางของคุณดีที่สุด - เรียบง่ายทำงานให้ลุล่วงและ "เบา" บนเห็บ สมบูรณ์แบบ.
BonanzaDriver

29

ยกโทษให้ฉันที่เป็น Stack virgin ... ฉันไม่แน่ใจว่าจะตอบกลับคำตอบของ Brian Ramsay อย่างไร ...

การใช้รอบจะไม่ทำงานสำหรับค่าที่สองระหว่าง 59.5 ถึง 59.99999 ค่าที่สองจะเป็น 60 ในช่วงเวลานี้ ใช้ trunc แทน ...

 double progress;

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

1
จริงๆแล้วแค่เอาพื้นและลำตัว / รอบออกทั้งหมด :)
InvulgoSoft

@StratFan คุณช่วยเพิ่มชั่วโมงในการตอบได้ไหม
Shmidt

27

หากคุณกำหนดเป้าหมายที่หรือสูงกว่า iOS 8 หรือ OS X 10.10 สิ่งนี้จะง่ายขึ้นมาก NSDateComponentsFormatterคลาสใหม่ช่วยให้คุณสามารถแปลงค่าที่กำหนดNSTimeIntervalจากค่าเป็นวินาทีเป็นสตริงที่แปลเป็นภาษาท้องถิ่นเพื่อแสดงให้ผู้ใช้เห็น ตัวอย่างเช่น:

วัตถุประสงค์ -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) อาจสะดวกกว่าในการส่งอินสแตนซ์ของตัวจัดรูปแบบNSDateComponentsหรือNSDateวัตถุสองชิ้นซึ่งสามารถทำได้เช่นกันโดยใช้วิธีการต่อไปนี้

วัตถุประสงค์ -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#>) {
    // ...
}

นี่เป็นวิธีที่เหมาะสมในการสร้างสตริงซึ่งมีการแปลอย่างเพียงพอ
SwiftArchitect

1
คำตอบนี้เป็นวิธี "Objective-C" มากกว่าและมีประโยชน์มากกว่าคำตอบที่ยอมรับ คุณไม่ต้องการswitchหรือif elseงบกับสิ่งนี้ NSDateComponentsFormatterดูแลมันทั้งหมด พิมพ์ชั่วโมงนาทีวินาทีโดยไม่ต้องกังวลใด ๆ
rustyMagnet

17

รหัสของ 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];
}

สิ่งนี้ไม่ได้แปล
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

เป็นตัวอย่างที่สมบูรณ์แบบจริงๆในการปกปิดวันที่
ravinder521986

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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.