Converting CMTime to human readable time in objective-c - objective-c

So I have a CMTime from a video. How do I convert it into a nice string like in the video time duration label in the Photo App. Is there some convenience methods that handle this? Thanks.
AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:url options:nil];
CMTime videoDuration = videoAsset.duration;
float videoDurationSeconds = CMTimeGetSeconds(videoDuration);

You can use this as well to get a video duration in a text format if you dont require a date format
AVURLAsset *videoAVURLAsset = [AVURLAsset assetWithURL:url];
CMTime durationV = videoAVURLAsset.duration;
NSUInteger dTotalSeconds = CMTimeGetSeconds(durationV);
NSUInteger dHours = floor(dTotalSeconds / 3600);
NSUInteger dMinutes = floor(dTotalSeconds % 3600 / 60);
NSUInteger dSeconds = floor(dTotalSeconds % 3600 % 60);
NSString *videoDurationText = [NSString stringWithFormat:#"%i:%02i:%02i",dHours, dMinutes, dSeconds];

There is always an extension ;)
import CoreMedia
extension CMTime {
var durationText:String {
let totalSeconds = Int(CMTimeGetSeconds(self))
let hours:Int = Int(totalSeconds / 3600)
let minutes:Int = Int(totalSeconds % 3600 / 60)
let seconds:Int = Int((totalSeconds % 3600) % 60)
if hours > 0 {
return String(format: "%i:%02i:%02i", hours, minutes, seconds)
} else {
return String(format: "%02i:%02i", minutes, seconds)
}
}
}
to use
videoPlayer?.addPeriodicTimeObserverForInterval(CMTime(seconds: 1, preferredTimescale: 1), queue: dispatch_get_main_queue()) { time in
print(time.durationText)
}

You can use CMTimeCopyDescription, it work really well.
NSString *timeDesc = (NSString *)CMTimeCopyDescription(NULL, self.player.currentTime);
NSLog(#"Description of currentTime: %#", timeDesc);
edit: okay, i read the question too fast, this is not what your wanted but could be helpful anyway for debuging.
edit: as #bcattle commented, the implementation i suggested contain a memory leak with ARC. Here the corrected version :
NSString *timeDesc = (NSString *)CFBridgingRelease(CMTimeCopyDescription(NULL, self.player.currentTime));
NSLog(#"Description of currentTime: %#", timeDesc);

Based on combination of the question and comments above, this is concise:
AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:url options:nil];
CMTime videoDuration = videoAsset.duration;
float videoDurationSeconds = CMTimeGetSeconds(videoDuration);
NSDate* date = [NSDate dateWithTimeIntervalSince1970:videoDurationSeconds];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
[dateFormatter setDateFormat:#"HH:mm:ss"]; //you can vary the date string. Ex: "mm:ss"
NSString* result = [dateFormatter stringFromDate:date];

Swift 3.0 ios 10 answer based codingrhythm answer...
extension CMTime {
var durationText:String {
let totalSeconds = CMTimeGetSeconds(self)
let hours:Int = Int(totalSeconds / 3600)
let minutes:Int = Int(totalSeconds.truncatingRemainder(dividingBy: 3600) / 60)
let seconds:Int = Int(totalSeconds.truncatingRemainder(dividingBy: 60))
if hours > 0 {
return String(format: "%i:%02i:%02i", hours, minutes, seconds)
} else {
return String(format: "%02i:%02i", minutes, seconds)
}
}
}

Swift 4.2 extension
extension CMTime {
var timeString: String {
let sInt = Int(seconds)
let s: Int = sInt % 60
let m: Int = (sInt / 60) % 60
let h: Int = sInt / 3600
return String(format: "%02d:%02d:%02d", h, m, s)
}
var timeFromNowString: String {
let d = Date(timeIntervalSinceNow: seconds)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "mm:ss"
return dateFormatter.string(from: d)
}
}

Simple extension I use for displaying video file duration.
import CoreMedia
extension CMTime {
var stringValue: String {
let totalSeconds = Int(self.seconds)
let hours = totalSeconds / 3600
let minutes = totalSeconds % 3600 / 60
let seconds = totalSeconds % 3600 % 60
if hours > 0 {
return String(format: "%i:%02i:%02i", hours, minutes, seconds)
} else {
return String(format: "%02i:%02i", minutes, seconds)
}
}
}

For example you can use NSDate and it's description method. You can specify any output format you want.
> `
// First, create NSDate object using
NSDate* d = [[NSDate alloc] initWithTimeIntervalSinceNow:seconds];
// Then specify output format
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:#"HH:mm:ss"];
// And get output with
NSString* result = [dateFormatter stringWithDate:d];`

here is the code for getting seconds from cmtime
NSLog(#"seconds = %f", CMTimeGetSeconds(cmTime));

Swift 3:
let time = kCMTimeZero
let timeString = time.toString()

A simplest way (without using NSDate and NSDateFormatter) to do this:-
Using Swift:-
func updateRecordingTimeLabel()
{
// Result Output = MM:SS(01:23)
let cmTime = videoFileOutput.recordedDuration
var durationInSeconds = Int(CMTimeGetSeconds(cmTime))
let durationInMinutes = Int(CMTimeGetSeconds(cmTime)/60)
var strDuMin = String(durationInMinutes)
durationInSeconds = durationInSeconds-(60*durationInMinutes)
var strDuSec = String(durationInSeconds)
if durationInSeconds < 10
{
strDuSec = "0"+strDuSec
}
if durationInMinutes < 10
{
strDuMin = "0"+strDuMin
}
// Output string
let str_output = strDuMin+":"+strDuSec
print("Result Output : [\(str_output)]")
}

Related

Get total step count for every date in HealthKit

What's the best way to get a total step count for every day recorded in HealthKit.
With HKSampleQuery's method initWithSampleType (see below) I can set a start and end date for the query using NSPredicate, but the method returns an array with many HKQuantitySamples per day.
- (instancetype)initWithSampleType:(HKSampleType *)sampleType
predicate:(NSPredicate *)predicate
limit:(NSUInteger)limit
sortDescriptors:(NSArray *)sortDescriptors
resultsHandler:(void (^)(HKSampleQuery *query,
NSArray *results,
NSError *error))resultsHandler
I guess I can query all recorded step counts and go through the array and calculate the total step count for each day, but I'm hoping for an easier solution as there will be thousands of HKSampleQuery objects. Is there a way to have initWithSampleType return a total step count per day?
You should use HKStatisticsCollectionQuery:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *interval = [[NSDateComponents alloc] init];
interval.day = 1;
NSDateComponents *anchorComponents = [calendar components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear
fromDate:[NSDate date]];
anchorComponents.hour = 0;
NSDate *anchorDate = [calendar dateFromComponents:anchorComponents];
HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
// Create the query
HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType
quantitySamplePredicate:nil
options:HKStatisticsOptionCumulativeSum
anchorDate:anchorDate
intervalComponents:interval];
// Set the results handler
query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) {
if (error) {
// Perform proper error handling here
NSLog(#"*** An error occurred while calculating the statistics: %# ***",error.localizedDescription);
}
NSDate *endDate = [NSDate date];
NSDate *startDate = [calendar dateByAddingUnit:NSCalendarUnitDay
value:-7
toDate:endDate
options:0];
// Plot the daily step counts over the past 7 days
[results enumerateStatisticsFromDate:startDate
toDate:endDate
withBlock:^(HKStatistics *result, BOOL *stop) {
HKQuantity *quantity = result.sumQuantity;
if (quantity) {
NSDate *date = result.startDate;
double value = [quantity doubleValueForUnit:[HKUnit countUnit]];
NSLog(#"%#: %f", date, value);
}
}];
};
[self.healthStore executeQuery:query];
Port to Swift with no dependency to SwiftDate library
let calendar = NSCalendar.current
let interval = NSDateComponents()
interval.day = 1
var anchorComponents = calendar.dateComponents([.day, .month, .year], from: NSDate() as Date)
anchorComponents.hour = 0
let anchorDate = calendar.date(from: anchorComponents)
// Define 1-day intervals starting from 0:00
let stepsQuery = HKStatisticsCollectionQuery(quantityType: stepsCount!, quantitySamplePredicate: nil, options: .cumulativeSum, anchorDate: anchorDate!, intervalComponents: interval as DateComponents)
// Set the results handler
stepsQuery.initialResultsHandler = {query, results, error in
let endDate = NSDate()
let startDate = calendar.date(byAdding: .day, value: -7, to: endDate as Date, wrappingComponents: false)
if let myResults = results{
myResults.enumerateStatistics(from: startDate!, to: endDate as Date) { statistics, stop in
if let quantity = statistics.sumQuantity(){
let date = statistics.startDate
let steps = quantity.doubleValue(for: HKUnit.count())
print("\(date): steps = \(steps)")
//NOTE: If you are going to update the UI do it in the main thread
DispatchQueue.main.async {
//update UI components
}
}
} //end block
} //end if let
}
healthStore?.execute(stepsQuery)
Modified #sebastianr's answer using core Swift classes, for just for testing I am returning only steps for just one day, once you have more days you can create a dictionary of Dates and step count and return it
func getStepCountPerDay(completion:#escaping (_ count: Double)-> Void){
guard let sampleType = HKObjectType.quantityType(forIdentifier: .stepCount)
else {
return
}
let calendar = Calendar.current
var dateComponents = DateComponents()
dateComponents.day = 1
var anchorComponents = calendar.dateComponents([.day, .month, .year], from: Date())
anchorComponents.hour = 0
let anchorDate = calendar.date(from: anchorComponents)
let stepsCumulativeQuery = HKStatisticsCollectionQuery(quantityType: sampleType, quantitySamplePredicate: nil, options: .cumulativeSum, anchorDate: anchorDate!, intervalComponents: dateComponents
)
// Set the results handler
stepsCumulativeQuery.initialResultsHandler = {query, results, error in
let endDate = Date()
let startDate = calendar.date(byAdding: .day, value: 0, to: endDate, wrappingComponents: false)
if let myResults = results{
myResults.enumerateStatistics(from: startDate!, to: endDate as Date) { statistics, stop in
if let quantity = statistics.sumQuantity(){
let date = statistics.startDate
let steps = quantity.doubleValue(for: HKUnit.count())
print("\(date): steps = \(steps)")
completion(steps)
//NOTE: If you are going to update the UI do it in the main thread
DispatchQueue.main.async {
//update UI components
}
}
} //end block
} //end if let
}
HKHealthStore().execute(stepsCumulativeQuery)
}
Here is a translation that currently works for Swift 2.0, using the SwiftDate library.
let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
let startDate = NSDate().beginningOfDay().oneWeekAgo()
let interval = NSDateComponents()
interval.day = 1
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: NSDate(), options: .StrictStartDate)
let query = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: predicate, options: [.CumulativeSum], anchorDate: NSDate().begginingOfDay(), intervalComponents:interval)
query.initialResultsHandler = { query, results, error in
let endDate = NSDate()
let startDate = NSDate().beginningOfDay().oneWeekAgo()
if let myResults = results{
myResults.enumerateStatisticsFromDate(startDate, toDate: endDate) {
statistics, stop in
if let quantity = statistics.sumQuantity() {
let date = statistics.startDate
let steps = quantity.doubleValueForUnit(HKUnit.countUnit())
print("\(date): steps = \(steps)")
}
}
}
}
healthKitStore.executeQuery(query)
I wrapped mine in a completion block (objective -c). I found what was best was to set the startDate for the query to todays date at midnight. Hope this helps, feel free to copy/paste to get started
-(void)fetchHourlyStepsWithCompletionHandler:(void (^)(NSMutableArray *, NSError *))completionHandler {
NSMutableArray *mutArray = [NSMutableArray new];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *startDate = [calendar dateBySettingHour:0 minute:0 second:0 ofDate:[NSDate date] options:0];
NSDate *endDate = [NSDate date]; // Whatever you need in your case
HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
// Your interval: sum by hour
NSDateComponents *intervalComponents = [[NSDateComponents alloc] init];
intervalComponents.hour = 1;
// Example predicate
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionStrictStartDate];
HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:type quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum anchorDate:startDate intervalComponents:intervalComponents];
query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) {
[results enumerateStatisticsFromDate:startDate toDate:endDate
withBlock:^(HKStatistics *result, BOOL *stop) {
if (!result) {
if (completionHandler) {
completionHandler(nil, error);
}
return;
}
HKQuantity *quantity = result.sumQuantity;
NSDate *startDate = result.startDate;
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
formatter.dateFormat = #"h a";
NSString *dateString = [formatter stringFromDate:startDate];
double steps = [quantity doubleValueForUnit:[HKUnit countUnit]];
NSDictionary *dict = #{#"steps" : #(steps),
#"hour" : dateString
};
[mutArray addObject:dict];
}];
if (completionHandler) {
completionHandler(mutArray, error);
}
};
[self.healthStore executeQuery:query];
}
With Updated Swift 2.0 & SwiftDate library.
let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
let startDate = NSDate().beginningOfDay
let interval = NSDateComponents()
interval.day = 1
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: NSDate(), options: .StrictStartDate)
let query = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: predicate, options: [.CumulativeSum], anchorDate: NSDate().beginningOfDay, intervalComponents:interval)
query.initialResultsHandler = { query, results, error in
let endDate = NSDate()
let startDate = NSDate().beginningOfDay
if let myResults = results{
myResults.enumerateStatisticsFromDate(startDate, toDate: endDate) {
statistics, stop in
if let quantity = statistics.sumQuantity() {
let date = statistics.startDate
let steps = quantity.doubleValueForUnit(HKUnit.countUnit())
print("\(date): steps = \(steps)")
}
}
}
}
healthKitStore.executeQuery(query)

NSString to static int?

Ok here is the problem, I have three NSStrings with int values, when the view loads this needs to run:
NSCalendar* gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
unsigned int uintFlags = NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents* differenceComponents = [gregorian components:uintFlags
fromDate:quitDate toDate:nowDate options:0];
NSString *hours1 = [NSString stringWithFormat:#"%d",[differenceComponents hour]];
hours = hours1;
NSString *minutes1 = [NSString stringWithFormat:#"%d",[differenceComponents minute]];
minutes = minutes1;
NSString *seconds1 = [NSString stringWithFormat:#"%d",[differenceComponents second]];
seconds = seconds1;
Those NSString now have int values in it, so I can't set int's to static any suggestions?
I wanted to do this way so I won't it...
- (void)updater:(id)sender {
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self
selector:#selector(timer:) userInfo:nil repeats:YES];
}
- (void)timer:(id)sender {
// I get error right here that says (initialize
// element is not a compile-contstant)
static int hour = hours.intValue;
static int minute = minutes.intValue;
static int second = seconds.intValue;
NSString *sec = [NSString stringWithFormat:#"%i",second];
if (seconds1 < 10) {
sec = [NSString stringWithFormat:#"0%i",second];
}
NSString *min = [NSString stringWithFormat:#"%i",minute];
if (minutes1 < 10) {
min = [NSString stringWithFormat:#"0%i",minute];
}
NSString *hours5 = [NSString stringWithFormat:#"%i",hour];
NSString *timerTime = [NSString stringWithFormat:#"%#:%#:%#" ,hours5 ,min ,sec];
label1.text = timerTime;
seconds1 ++;
if (seconds1 > 59) {
seconds1 = 00;
minutes1 ++;
}
if (minutes1 > 59) {
minutes1 = 00;
hours1 ++;
}
}
Why do you want to use static? I don't get the point of making those variables static.
And why using NSString to encapsulate your int values as well?!?? Why not store the int values directly?
Actually you shouldn't either rely of adding the seconds yourself at each execution of the timer method, because an NSTimer can drift, so after some time (quite long time, sure, but still) you can have this drift affect the "seconds" part. Better recompute the timeInterval each time. And why bother adding the leading "0" yourself, when you could use %02i format instead?
Actually your code can be as simple and concise as this:
-(void)timer:(NSTimer*)sender
{
NSTimeInterval elapsedTime = -[quitDate timeIntervalSinceNow];
label1.text = [NSString stringWithFormat:#"%02i:%02i:%02i",
(int)elapsedTime/3600,
((int)elapsedTime/60 ) % 60,
((int)elapsedTime ) % 60];
}
static variable can't be "dynamic". The compiler should know what the value has been assigned before the program run.
just move them to instance variables of said view controller, and set/calculate their values at initialization. done.
The reason why you would want those integers to be static eludes me, still here's a trick that will let you have static (global) data that can be initialized in runtime (dynamically). Just create a class method that manages it:
#interface MyClasss : NSObject
+ (NSDateComponents *)dateComponents;
+ (NSInteger)hours;
+ (NSInteger)minutes;
+ (NSInteger)seconds;
#end
#implementation MyClass
+ (NSDateComponents *)dateComponents
{
NSCalendar* gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
unsigned int uintFlags = NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents* differenceComponents = [gregorian components:uintFlags
fromDate:quitDate toDate:nowDate options:0];
}
+ (NSInteger)hours
{
NSString *hoursText = [NSString stringWithFormat:#"%d",[self dateComponents hour]];
return hoursText.integerValue;
}
+ (NSInteger)minutes
{
NSString *minutesText = [NSString stringWithFormat:#"%d",[self dateComponents minute]];
return minutesText.integerValue;
}
+ (NSInteger)seconds
{
NSString *secondsText = [NSString stringWithFormat:#"%d",[self dateComponents second]];
return secondsText.integerValue;
}
#end
Now you have static data at your disposal which can be accessed without instantiating an object:
NSInteger hours = [MyClass hours];

How to convert "3:31" mm:ss from string to integer representing seconds [duplicate]

This question already has answers here:
Convert seconds into minutes and seconds
(6 answers)
Closed 8 years ago.
I'm relatively new to programming for iOS using Xcode and Objective-C.
I need to be able to convert the length of a song, for example 3:31 that is a string into an integer representing seconds. so 3:31 (mm:ss) would be 211 seconds, and then back from 211 to 3:31.
Any help to get me started would be appreciated.
To convert the time in seconds to the string you described, you can use the following code:
int songLength = 211;
int minutes = songLength / 60;
int seconds = songLength % 60;
NSString *lengthString = [NSString stringWithFormat:#"%d:%02d", minutes, seconds];
Note the use of 0 in %02d This makes values like 188 transformed into 3:08 instead of 3:8.
You can use NSDateFormatter to get seconds and minutes from the time string:
NSString *timeString = #"3:31";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"mm:ss";
NSDate *timeDate = [formatter dateFromString:timeString];
formatter.dateFormat = #"mm";
int minutes = [[formatter stringFromDate:timeDate] intValue];
formatter.dateFormat = #"ss";
int seconds = [[formatter stringFromDate:timeDate] intValue];
int timeInSeconds = seconds + minutes * 60;
Edit: Adding hours
int songLength = 4657;
int hours = songLength / 3600;
int minutes = (songLength % 3600) / 60;
int seconds = songLength % 60;
NSString *lengthString = [NSString stringWithFormat:#"%d:%02d:%02d", hours, minutes, seconds];
And
NSString *timeString = #"2:3:31";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"hh:mm:ss";
NSDate *timeDate = [formatter dateFromString:timeString];
formatter.dateFormat = #"hh";
int hours = [[formatter stringFromDate:timeDate] intValue];
formatter.dateFormat = #"hh";
int minutes = [[formatter stringFromDate:timeDate] intValue];
formatter.dateFormat = #"ss";
int seconds = [[formatter stringFromDate:timeDate] intValue];
int timeInSeconds = seconds + minutes * 60 + hours * 3600;
You can split the string at :, and calculate the result like this:
NSArray* tokens = [lengthStr componentsSeparatedByString:#":"];
NSUInteger lengthInSeconds = 0;
for (int i = 0 ; i != tokens.count ; i++) {
lengthInSeconds = 60*lengthInSeconds + [[tokens objectAtIndex:i] integerValue];
}
To format the value back, use
[NSString stringWithFormat:#"%d:%02d", lengthInSeconds / 60, lengthInSeconds % 60];
NSString has tons of great methods to help with this type of thing.
You can use componentsSeperatedByString to break up your minutes and seconds
NSArray *listItems = [list componentsSeparatedByString:#":"];
then convert the strings to ints with intValue.
Finally, convert your minutes to seconds and add it all up.
You can get details on all the great things NSString does with the class refernce
(NSString Reference)
This is a method I use in one of my apps to convert a long to mm:ss format:
long seconds = //anything;
NSString *output = [NSString stringWithFormat:#"%02lu:%02lu",seconds/60,seconds-(seconds/60)*60];
If you're using an int you just have to replace lu in the format with i like this:
[NSString stringWithFormat:#"%02i:%02i",seconds/60,seconds-(seconds/60)*60];
The 02 makes sure that the output is always two digits long. 65 seconds will be displayed as 01:05. If you would use %i:%i in the format the output for 65 seconds would look like this: 1:5 and thats not how you want it to look.

NSTimeInterval Formatting

I want to take my NSTimeInterval and format it into a string as 00:00:00 (hours, minutes, seconds). What is the best way to do this?
Since iOS 8.0 there is now NSDateComponentsFormatter which has a stringFromTimeInterval: method.
[[NSDateComponentsFormatter new] stringFromTimeInterval:timeInterval];
"Best" is subjective. The simplest way is this:
unsigned int seconds = (unsigned int)round(myTimeInterval);
NSString *string = [NSString stringWithFormat:#"%02u:%02u:%02u",
seconds / 3600, (seconds / 60) % 60, seconds % 60];
UPDATE
As of iOS 8.0 and Mac OS X 10.10 (Yosemite), you can use NSDateComponentsFormatter if you need a locale-compliant solution. Example:
NSTimeInterval interval = 1234.56;
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute |
NSCalendarUnitSecond;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
NSString *string = [formatter stringFromTimeInterval:interval];
NSLog(#"%#", string);
// output: 0:20:34
However, I don't see a way to force it to output two digits for the hour, so if that's important to you, you'll need to use a different solution.
NSTimeInterval interval = ...;
NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
NSString *formattedDate = [dateFormatter stringFromDate:date];
NSLog(#"hh:mm:ss %#", formattedDate);
swift 4.2
extension Date {
static func timestampString(timeInterval: TimeInterval) -> String? {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad
formatter.maximumUnitCount = 0
formatter.allowedUnits = [.hour, .minute, .second]
return formatter.string(from: timeInterval)
}
}
Test code:
let hour = 60 * 50 * 32
Date.timestampString(timeInterval: TimeInterval(hour))
// output "26:40:00"
Change unitStyle to get different styles. like formatter.unitsStyle = .abbreviated get
output: "26h 40m 0s"
A Swift version of #Michael Frederick's answer :
let duration: NSTimeInterval = ...
let durationDate = NSDate(timeIntervalSince1970: duration)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(name: "UTC")
let durationString = dateFormatter.stringFromDate(durationDate)

Counting down the days - iPhone Count Down Timer

I’m trying to make a counter which shows the number of days until we leave on a trip to Europe. It’s only about 70 days (as of today) so I don’t believe that I should have to worry about astronomically large numbers or anything, but I really am stumped - I’ve attached the code that some friends have given me, which don’t work either. Trust me when I say I’ve tried everything I can think of - and before anyone bites my head off, which I have seen done on these forums, yes I did look very extensively at the Apple Documentation, however I’m not 100% sure where to start - I’ve tried NSTimer, NSDate and all their subclasses and methods, but there’s nothing that jumps out immediately.
In terms of what I think I should actually be doing, I think I need to somehow assign an integer value for the “day” today/ now/ the current day, which will change dynamically using the [NSDate date] and then the same for the date that we leave. The countdown is just updating when the method gets called again (I can do this using NSTimer if need be) and the value that is displayed on the countdown is the differnce between these two values.
I don’t especially want to have a flashing kind of thing that updates every second until we leave - personally I think that’s tacky, but if anyone knows how then I’d appreciate it for future reference.
I’ve also done an extensive search of google, and I may simply be using the wrong search terms, but I can’t find anything there either.
Any help is greatly appreciated.
Thank you very much.
Michaeljvdw
- (void)countDownMethod {
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:startDay];
[comps setMonth:startMonth];
[comps setYear:startYear];
[comps setHour:startHour];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:comps];
NSLog(#"%#",date);
[gregorian release];
[comps release];
NSTimeInterval diff = [date timeIntervalSinceNow];
int diffInt = diff;
NSString *days = [NSString stringWithFormat:#"%d",diffInt/86400];
day0.text = #"0";
day1.text = #"0";
day2.text = #"0";
NSLog(#"Days Length: %d",days.length);
if(days.length >= 1){
day2.text = [days substringFromIndex:days.length - 1];
if(days.length >= 2){
day1.text = [days substringWithRange:NSMakeRange(days.length - 2, 1)];
if(days.length >= 3){
day0.text = [days substringWithRange:NSMakeRange(days.length - 3, 1)];
}
}
}
NSString *hours = [NSString stringWithFormat:#"%d",(diffInt%86400)/3600];
hour0.text = #"0";
hour1.text = #"0";
NSLog(#"Hours Length: %d",hours.length);
if(hours.length >= 1){
hour1.text = [hours substringFromIndex:hours.length - 1];
if(hours.length >= 2){
hour0.text = [hours substringWithRange:NSMakeRange(hours.length - 2, 1)];
}
}
NSString *minutes = [NSString stringWithFormat:#"%d",((diffInt%86400)%3600)/60];
minute0.text = #"0";
minute1.text = #"0";
NSLog(#"Minutes Length: %d",minutes.length);
if(minutes.length >= 1){
minute1.text = [minutes substringFromIndex:minutes.length - 1];
if(minutes.length >= 2){
minute0.text = [minutes substringWithRange:NSMakeRange(minutes.length - 2, 1)];
}
}
}
If you know the time in seconds between 2 dates (your NSTimeInterval) then you can easily convert that into a string in the format days:hours:mins:secs as follows.
- (NSString*)secsToDaysHoursMinutesSecondsString:(NSTimeInterval)theSeconds {
div_t r1 = div(theSeconds, 60*60*24);
NSInteger theDays = r1.quot;
NSInteger secsLeftFromDays = r1.rem;
div_t r2 = div(secsLeftFromDays, 60*60);
NSInteger theHours = r2.quot;
NSInteger secsLeftFromHours = r2.rem;
div_t r3 = div(secsLeftFromHours, 60);
NSInteger theMins = r3.quot;
NSInteger theSecs = r3.rem;
NSString* days;
if (theDays < 10) { // make it 2 digits
days = [NSString stringWithFormat:#"0%i", theDays];
} else {
days = [NSString stringWithFormat:#"%i", theDays];
}
NSString* hours;
if (theHours < 10) { // make it 2 digits
hours = [NSString stringWithFormat:#"0%i", theHours];
} else {
hours = [NSString stringWithFormat:#"%i", theHours];
}
NSString* mins;
if (theMins < 10) { // make it 2 digits
mins = [NSString stringWithFormat:#"0%i", theMins];
} else {
mins = [NSString stringWithFormat:#"%i", theMins];
}
NSString* secs;
if (theSecs < 10) { // make it 2 digits
secs = [NSString stringWithFormat:#"0%i", theSecs];
} else {
secs = [NSString stringWithFormat:#"%i", theSecs];
}
return [NSString stringWithFormat:#"%#:%#:%#:%#", days, hours, mins,secs];
}
//Another simple way to get the numbers of days difference to a future day from today.
NSTimeInterval todaysDiff = [todayDate timeIntervalSinceNow];
NSTimeInterval futureDiff = [futureDate timeIntervalSinceNow];
NSTimeInterval dateDiff = futureDiff - todaysDiff;
div_t r1 = div(dateDiff, 60*60*24);
NSInteger theDays = r1.quot;
label.text = [NSString stringWithFormat:#"%i", theDays];