NSTimeInterval tới HH: mm: ss?


85

Nếu tôi có NSTimeInterval được đặt thành 200.0, có cách nào để chuyển đổi nó thành 00:03:20 không, tôi đã nghĩ mình có thể khởi tạo NSDate với nó và sau đó sử dụng NSDateFormatter bằng HH: mm: ss. Câu hỏi của tôi là, có một cách nhanh chóng để làm điều này hay tôi phải tự mình chia nhỏ số và sử dụng [NSString stringWithFormat: %02d:%02d:%02d, myHour, myMin, mySec]?

Câu trả lời:


198

Không cần sử dụng NSDateFormatterhoặc bất cứ điều gì khác ngoài phân chia và mô-đun. NSTimeIntervalchỉ là một đôi chứa giây.

Nhanh

func stringFromTimeInterval(interval: NSTimeInterval) -> String {
    let interval = Int(interval)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}

Objective-C

- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
    NSInteger ti = (NSInteger)interval;
    NSInteger seconds = ti % 60;
    NSInteger minutes = (ti / 60) % 60;
    NSInteger hours = (ti / 3600);
    return [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
}

Được đánh giá cao, đó là những gì tôi đang nghĩ nhưng tôi chỉ muốn kiểm tra rằng tôi không thiếu thứ gì đó đã được đưa vào như một phần của iOS SDK.
dimgoat

1
Tôi muốn chỉ ra rằng ":" chỉ hoạt động như một dấu phân tách trong tiếng Anh và một số ngôn ngữ khác. Ví dụ, tiếng Phần Lan sử dụng "." - như thế này "15.02.59"
sgosha

@sgosha, chính xác, thông thường Apple có xu hướng cung cấp các bộ định dạng cho những thứ này. Thay vào đó, tôi có nên sử dụng một chuỗi được bản địa hóa để định dạng không?
Gerry Shaw

20
đây là câu trả lời sai vì nó không bản địa hóa dấu phân cách (như các nhận xét khác đề cập). bằng cách sử dụng NSDateCompomentsFormatter, bạn có thể định dạng chính xác khoảng thời gian của mình trong một dòng duy nhất, ví dụ NSDateComponentsFormatter().stringFromTimeInterval(NSTimeInterval(duration))nhanh chóng
Ilias Karim

4
Để bản địa hóa và kiểm tra trong tương lai, giải pháp chính xác là sử dụng NSDateComponentsFormatter như được mô tả bởi @jrc
voidref

102

Trên iOS 8, sử dụng NSDateComponentsFormatter.

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

đầu ra "3:20".

NSDateComponentsFormatter *dateComponentsFormatter = [[NSDateComponentsFormatter alloc] init];
dateComponentsFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
dateComponentsFormatter.allowedUnits = (NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond);
NSLog(@"%@", [dateComponentsFormatter stringFromTimeInterval:200.0]);

kết quả đầu ra "0:03:20".


2
Cập nhật tốt đẹp. Nhưng nếu nó thực sự chỉ là một phép tính đơn giản như vậy, thì việc sử dụng các đối tượng này sẽ không phải là một chi phí lớn (miễn là không có định dạng động liên quan)?
Julian F. Weinert

2
bạn cần định dạng để đảm bảo chuỗi xuất hiện một cách chính xác cho nhau miền địa phương, vv
Max MacLeod

Nhận xét thực sự nhỏ, nhưng thật kỳ lạ khi đưa ra một ví dụ về hàm C cho câu hỏi ObjectiveC. Có lẽ đáng để thay đổi nó thành định dạng ObjectiveC?
Rilakkuma

Đã tiết kiệm cho tôi một tấn mã! Đây là cách tôi sử dụng nó cho OrangeIRC .
ahyattdev 27/12/16

17

Câu trả lời của onmyway133 phiên bản Swift 3 :

import Foundation

func format(_ duration: TimeInterval) -> String {
    let formatter = DateComponentsFormatter()
    formatter.zeroFormattingBehavior = .pad
    formatter.allowedUnits = [.minute, .second]

    if duration >= 3600 {
        formatter.allowedUnits.insert(.hour)
    }

    return formatter.string(from: duration)!
}


print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00

Việc tạo DateComponentsFormatter có tốn kém về hiệu suất hay không, giống như DateFormatter hoặc NumberFormatter?
Moshe

1
Thay vì kiểm tra xem có giá trị giờ hay không, cài đặt zeroFormattingBehaviorthành [.dropLeading, .pad]có thể là một tùy chọn tốt hơn (ít mã hơn).
MaddTheSane

Các nhận xét dường như không chính xác. Mã này dẫn đến: 00:12, 01:05, 29:10, 01:04:50, 12:42:00
Jordan H

10

Một số dòng mã bổ sung, nhưng tôi cảm thấy sử dụng NSDateComponents sẽ cho giá trị chính xác hơn.

- (NSString *)getTimeRepresentationFromDate:(NSDate *)iDate withTimeInterval:(NSTimeInterval)iTimeInterval {
    NSString *aReturnValue = nil;
    NSDate *aNewDate = [iDate dateByAddingTimeInterval:iTimeInterval]; 

    unsigned int theUnits = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSCalendar *aCalender = [NSCalendar currentCalendar];
    NSDateComponents *aDateComponents = [aCalender components:theUnits fromDate:iDate toDate:aNewDate options:0];

    aReturnValue = [NSString stringWithFormat:@"%d:%d:%d", [aDateComponents hour], [aDateComponents minute], [aDateComponents second]];

    return aReturnValue;
}

Phương thức trên sử dụng 2 ngày mà TimeInterval được tạo. Bạn cũng có thể chuyển [NSDate date] vào tham số iDate làm giá trị mặc định.
Roshit

2
Theo cách nào thì phương pháp này "chính xác hơn" so với phương pháp mà @ matthias-bauch sử dụng?
jb

1
với phương pháp này, bạn nhận được khoảng thời gian tính bằng giây, giờ, phút, tức là theo 60 trong khi câu trả lời của @ matthias-bauch cung cấp cho bạn ở dạng thập phân, ví dụ: nếu bạn đợi đủ thời gian, bạn sẽ thấy 1 phút 79 giây thay vì 2 phút 19 giây
Ashish Pisey

Đây là một giải pháp tốt hơn nhiều so với giải pháp được chấp nhận. Việc sử dụng ":" vẫn còn là một vấn đề đối với quá trình quốc tế hóa, nhưng ít nhất thì điều này là mạnh mẽ trong những ngày nhuận và ranh giới tiết kiệm ánh sáng ban ngày.
evanflash

@AshishPisey Các ngăn chặn hành modulo bất cứ điều gì lớn hơn 59.
Matthias Bauch

8

Trong Swift 2 , iOS 8+ . Điều này đảm bảo chúng tôi chỉ hiển thị giờ khi cần thiết

func format(duration: NSTimeInterval) -> String {
  let formatter = NSDateComponentsFormatter()
  formatter.zeroFormattingBehavior = .Pad

  if duration >= 3600 {
    formatter.allowedUnits = [.Hour, .Minute, .Second]
  } else {
    formatter.allowedUnits = [.Minute, .Second]
  }

  return formatter.stringFromTimeInterval(duration) ?? ""
}

Vì vậy, bạn có

print(format(12)) // 0:12
print(format(65)) // 1:05
print(format(1750)) // 29:10
print(format(3890)) // 1:04:50
print(format(45720)) // 12:42:00

4
NSTimeInterval ti = 3667;
double hours = floor(ti / 60 / 60);
double minutes = floor((ti - (hours * 60 * 60)) / 60);
double seconds = floor(ti - (hours * 60 * 60) - (minutes * 60));

4

Swift 4

DateComponentsFormatter().string(from: <# TimeInterval #>)

Ví dụ:

DateComponentsFormatter().string(from: 59.0)

3

Để "mở rộng" gợi ý của Matthias Bauch, trong Swift, tôi sẽ đặt đây là một thuộc tính được tính toán của NSTimeInterval:

extension NSTimeInterval {
  var stringValue: String {
    let interval = Int(self)
    let seconds = interval % 60
    let minutes = (interval / 60) % 60
    let hours = (interval / 3600)
    return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
  }
}

Ưu điểm của điều này là nó được gắn vào NSTimeIntervalloại, không phải bộ điều khiển chế độ xem của bạn hoặc bất cứ nơi nào khác bạn đặt chức năng đó. Để sử dụng, bạn đi những thứ như sau:

let timeInterval = NSDate().timeIntervalSinceDate(start)        
self.elapsedTimeLabel.text = timeInterval.stringValue

Cảm ơn, Kenny! Trong trường hợp của tôi, tôi cần chúng một cách riêng biệt, vì vậy tôi đã thêm các biến bổ sung vào tiện ích mở rộng của bạn: "var seconds: Int {let period = Int (self); let seconds = period% 60; return seconds}", v.v. trong phút và giờ. Vì vậy, việc sử dụng đó sẽ là: print ( "phút dành: (timeInterval.minutes)")
Vitalii

3

Dựa trên câu trả lời của @ onmyway133, đây là phiên bản Swift 4:

func format(duration: TimeInterval) -> String {
    let formatter = DateComponentsFormatter()
    formatter.zeroFormattingBehavior = .pad

    if duration >= 3600 {
        formatter.allowedUnits = [.hour, .minute, .second];
    } else {
        formatter.allowedUnits = [.minute, .second];
    }

    return formatter.string(from: duration) ?? "";
}

0

trực tiếp từ apple docs: trong tệp h:

 @property(strong,nonatomic)NSDateComponentsFormatter *timerFormatter;

trong tệp m

@synthesize timerFormatter;

- (void)viewDidLoad {
[super viewDidLoad];
NSDateComponentsFormatter *timerFormatter = [[NSDateComponentsFormatter alloc] init];
timerFormatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional; 
//10:59 Positional THIS ONE DOES NOT SEEM TO WORK iOS<9 WHEN <1Minute JUST SHOWS 01, 10m 59s Abbreviated, 10min 59sec Short, 10minutes 59seconds Full ...
timerFormatter.allowedUnits = NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
}

Bất cứ khi nào bạn cần chuyển đổi NSTimeInterval timeInterval thành chuỗi hh: mm: ss, hãy làm như sau:

NSString *txt=[timerFormatter stringFromTimeInterval:timeInterval];

0

Tôi đoán, phần hẹn giờ sẽ kết thúc. Vì mã của Matthias đang tạo ra vấn đề đó trong vài giây, tôi sử dụng mã sửa đổi sau đây từ mã của Matthias

    - (NSString *)stringFromTimeInterval:(NSTimeInterval)interval {
        int ti = (int) ceil(interval);
        int seconds = ti % 60;
        int minutes = (ti / 60) % 60;
        int hours = (ti / 3600);
        return [NSString stringWithFormat:@"%02d:%02d:%02d",hours, minutes, seconds];
    }

0

Phiên bản Objective C của câu trả lời của onmyway133

- (NSString*) formatTimeInterval:(NSTimeInterval) timeInterval {

    NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];

    formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;

    if (timeInterval > 3600) {
        formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    } else {
        formatter.allowedUnits = NSCalendarUnitMinute | NSCalendarUnitSecond;
    }

    return [formatter stringFromTimeInterval:timeInterval];
}
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.