Làm thế nào để chuyển đổi NSTimeInterval (giây) thành phút


104

Tôi đã nhận được một số tiền secondsđã qua từ một sự kiện nhất định. Nó được lưu trữ trong một NSTimeIntervalkiểu dữ liệu.

Tôi muốn chuyển đổi nó thành minutesseconds.

Ví dụ tôi có: "326,4" giây và tôi muốn chuyển đổi nó thành chuỗi sau: "5:26".

Cách tốt nhất để đạt được mục tiêu này là gì?

Cảm ơn.

Câu trả lời:


147

mã giả:

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

90
Tôi nghĩ cũng cần nhắc lại rằng NSTimerInterval chỉ là một định dạng cho double.
Armentage

4
Xem câu trả lời của Albaregar - đó là một cách tốt hơn để làm điều này (nhiều mã hơn nhưng linh hoạt hơn, có thể bảo trì được)
benvolioT 12/09/10

1
Tuy nhiên, mã đó rất đắt. Để chuyển đổi nhanh thời lượng tính bằng giây, câu trả lời này tốt hơn.
SpacyRicochet

2
Xin lưu ý rằng câu trả lời này sẽ cung cấp cho bạn những thứ như 1:60. Hãy xem câu trả lời của StratFan gần với sự thật hơn. Nhưng loại bỏ sàn và vòng và bạn sẽ được ở nhà tự do.
InvulgoSoft

Câu trả lời của Mick MacCallum dưới đây tại thời điểm viết nhận xét này dường như được cập nhật và thực hiện nhiều nhất bằng cách sử dụng API gốc.
Tomasz Nazarenko

183

Mô tả ngắn gọn

  1. Câu trả lời từ Brian Ramsay là thuận tiện hơn nếu bạn chỉ muốn chuyển đổi sang phút.
  2. Nếu bạn muốn Cocoa API làm điều đó cho bạn và chuyển đổi NSTimeInterval của bạn không chỉ thành phút mà còn thành ngày, tháng, tuần, v.v., tôi nghĩ đây là một cách tiếp cận chung chung hơn
  3. Sử dụng phương pháp NSCalendar:

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

    • "Trả về, như một đối tượng NSDateComponents sử dụng các thành phần được chỉ định, sự khác biệt giữa hai ngày được cung cấp". Từ tài liệu API.

  4. Tạo 2 NSDate có sự khác biệt là NSTimeInterval bạn muốn chuyển đổi. (Nếu NSTimeInterval của bạn đến từ việc so sánh 2 NSDate, bạn không cần thực hiện bước này và thậm chí bạn không cần NSTimeInterval).

  5. Nhận báo giá của bạn từ NSDateComponents

Mã mẫu

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

Các vấn đề đã biết

  • Quá nhiều cho một chuyển đổi, bạn nói đúng, nhưng đó là cách API hoạt động.
  • Đề xuất của tôi: nếu bạn đã quen với việc quản lý dữ liệu thời gian của mình bằng NSDate và NSCalendar, API sẽ thực hiện công việc khó khăn cho bạn.

4
Chắc chắn là có rất nhiều cách giải quyết chỉ để thực hiện một chút chuyển đổi, nhưng nó cảm thấy có thể cấu hình, mô-đun và thực sự linh hoạt, hãy bỏ phiếu cho mã mẫu này @Albaregar.
Rigo Vides

2
+1 Để có câu trả lời cặn kẽ, tuy nhiên mã này khá đắt.
Nick Weaver vào

1
+1 ... một cảnh báo. Hãy cẩn thận khi sử dụng kiểu mã này nếu bạn cần làm tròn số giây phân số. Hành vi mặc định của - [Thành phần NSCalendar: fromDate: toDate: options:] có thể gây rối trong trường hợp thành phần ngàyDate trước 31,5 giây (ví dụ) so với fromDate - các thành phần trả về sẽ có 31 trong trường giây. Có một tham số tùy chọn của NSWrapCalendarComponents, nhưng từ thử nghiệm (giới hạn) mà tôi đã thực hiện với điều này, nó kết thúc đến giây gần nhất chứ không phải làm tròn lên hoặc xuống. Số dặm của bạn có thể thay đổi.
David Doyle

%ldnếu bạn đang ở trong máy 64 bit.
Anoop Vaidya

5
Những người tìm thấy điều này (như Nick Weaver) sẽ nghĩ rằng mã có vẻ như nó sẽ chậm. Nó không phải. Tôi đang làm một ứng dụng hẹn giờ và tôi vừa thử nghiệm phiên bản của Albaregar với thứ gì đó theo phong cách của Brian Ramsey (và những người khác) ... và thật ngạc nhiên, thậm chí bỏ phiếu 100 lần một giây (quá mức cần thiết) trên một thiết bị tương đối chậm (4S ) có sự khác biệt ít hơn 1% trong việc sử dụng bộ xử lý.
mmc

42

Tất cả những thứ này trông phức tạp hơn mức cần thiết! Đây là một cách ngắn gọn và thú vị để chuyển đổi khoảng thời gian thành giờ, phút và giây:

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;

Lưu ý khi bạn đặt float vào int, bạn sẽ tự động nhận được tầng (), nhưng bạn có thể thêm nó vào hai đầu tiên nếu nếu làm cho bạn cảm thấy tốt hơn :-)


Tuyệt vời! Tôi đã thử mã của Ramsay mặc dù nó có vẻ bị lỗi sau một giây.
uplearnedu.com

Bạn đang thiếu dấu chấm phẩy trong mã của mình nhưng nó sẽ không cho phép tôi chỉnh sửa để khắc phục.
Jeef

Tôi nghĩ cách tiếp cận của bạn là tốt nhất - đơn giản, hoàn thành công việc và "nhẹ tay". Hoàn hảo.
BonanzaDriver

29

Thứ lỗi cho tôi vì tôi là một trinh nữ của Stack ... Tôi không biết làm thế nào để trả lời câu trả lời của Brian Ramsay ...

Sử dụng vòng sẽ không hoạt động đối với các giá trị thứ hai giữa 59,5 và 59,99999. Giá trị thứ hai sẽ là 60 trong khoảng thời gian này. Sử dụng trunc thay thế ...

 double progress;

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

1
Trên thực tế, chỉ cần loại bỏ sàn và thân / vòng hoàn toàn. :)
InvulgoSoft

@StratFan Bạn có thể vui lòng thêm giờ vào câu trả lời của mình không?
Shmidt

27

Nếu bạn đang nhắm mục tiêu ở iOS 8 hoặc OS X 10.10 trở lên, điều này sẽ dễ dàng hơn rất nhiều. Lớp mới NSDateComponentsFormattercho phép bạn chuyển đổi một NSTimeIntervalgiá trị đã cho từ giá trị của nó trong vài giây thành một chuỗi được bản địa hóa để hiển thị cho người dùng. Ví dụ:

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

Nhanh

let interval = 326.4

let componentFormatter = NSDateComponentsFormatter()

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

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

NSDateCompnentsFormattercũng cho phép đầu ra này ở dạng dài hơn. Có thể tìm thấy thêm thông tin trong bài báo NSFormatter của NSHipster . Và tùy thuộc vào những lớp nào bạn đang làm việc (nếu không NSTimeInterval), có thể thuận tiện hơn để chuyển cho trình định dạng một thể hiện của NSDateComponentshoặc hai NSDateđối tượng, điều này cũng có thể được thực hiện thông qua các phương thức sau.

Objective-C

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

Nhanh

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

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

Đây là cách thích hợp để tạo chuỗi, được bản địa hóa đầy đủ
SwiftArchitect.

1
Câu trả lời này là "Objective-C" và hữu ích hơn câu trả lời được chấp nhận. Bạn không cần switchhoặc if elsetuyên bố với điều này. NSDateComponentsFormatterchăm sóc tất cả. Giờ, phút, giây được in mà không cần lo lắng.
gỉMagnet

17

Mã của Brian Ramsay, không được giả danh:

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

Điều này không bản địa hóa
SwiftArchitect

7

Đây là phiên bản 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)
}

Có thể được sử dụng như thế này:

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

Kết quả đầu ra:

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

ví dụ thực sự hoàn hảo của nó để bí mật hẹn hò
ravinder521986

5

Vì về cơ bản nó là một ...

Chia cho 60,0 và lấy phần tích phân và phần phân số.

Phần tích phân sẽ là toàn bộ số phút.

Nhân phần phân số với 60,0 một lần nữa.

Kết quả sẽ là những giây còn lại.


3

Hãy nhớ rằng câu hỏi ban đầu là về đầu ra chuỗi, không phải mã giả hoặc các thành phần chuỗi riêng lẻ.

Tôi muốn chuyển nó thành chuỗi sau: "5:26"

Nhiều câu trả lời thiếu các vấn đề quốc tế hóa và hầu hết đều thực hiện các phép tính toán bằng tay. Tất cả chỉ là thế kỷ 20 ...

Không tự làm Toá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


Tận dụng thư viện

Nếu bạn thực sự muốn các thành phần riêng lẻ và mã dễ đọc, hãy xem SwiftDate :

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

5


Tín dụng cho @mickmaccallum@polarwar để sử dụng đầy đủDateComponentsFormatter


0

Tôi đã thực hiện điều này như thế nào trong Swift (bao gồm định dạng chuỗi để hiển thị nó là "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

Phiên bản 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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.