ios minutes to time - ios

I want to go from minutes as an int (eg 92) to a string of 1:32. Is there a fancy way to do this using objc or I'm I stuck with figuring it out the old-fashioned way?

I do not believe there is a function to do this, but it is simple enough to do on your own.
int hour = minutes / 60;
int min = minutes % 60;
NSString *timeString = [NSString stringWithFormat: %#"%d:%02d", hour, min];
The '02' will pad the results so there are always two digits in the minutes place. It may be useful to look at the NSDate Class Reference as it may save you time if you want to do calculations on the result.

I think you can find the answer here: NSTimeInterval to NSDate
The int you talking about should be NSTimeInterval (that is just double), convert it to a NSDate object and then format it using the NSDateFormatter with: HH:mm.
It can also could be more useful "extend" using categories NSDate object
#interface NSDate (Minutes)
and put there a method convert minutes to HH:mm (maybe could be better to move the format string as method parameter) so you never more need think about it.

Related

Time difference with NSDateComponents

I'm building an app whereas I need to calculate the time between two NSDates.
I've subclassed NSObject and named it "MyObject" (simplified for the sake of this question).
It holds these two properties
#property (nonatomic, strong) NSDate *startDate;
#property (nonatomic, strong) NSDate *endDate;
I have an array storing x number of MyObjects, which I loop through like so
NSTimeInterval totalInterval = 0;
for (MyObject *currentObject in _listOfItems)
{
totalInterval += [currentObject.endDate timeIntervalSinceDate:currentObject.startDate];
}
I'm using totalInterval to summarise the length of all the "spans" combined. I'm doing this by setting up 2 NSDates, simply for the sake of calculating the difference.
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:totalInterval sinceDate:date1];
I'm setting up these flags:
unsigned int unitFlags = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitDay | NSCalendarUnitMonth;
And return the result as NSDateComponent like so:
return [sysCalendar components:unitFlags fromDate:date1 toDate:date2 options:0];
My question: When I used the units above, I had the wrong result - namely 11h 20m when the real answer is about 83h. I learned that I was needlessly specifying the NSCalendarUnitDay and NSCalendarUnitMonth units. After reading the docs, I read that "There is no need to specify any more components than those in which you are interested" and I removed the two needlessly specified units. This gave me the right result, but how come? Why would it report the wrong result by simply specifying more units?
Thank you!
The calculation will always begin with the largest units that you've asked for. So if you ask for days and hours, but then only inspect hours, you will see the actual total number of hours modulo 24. This applies to any date decomposition that NSCalendar performs.
Why would it report the wrong result by simply specifying more units?
The NSDateComponents represents all of the time between the two dates (300.000 seconds in your case), specified in a number of days (3), hours (11) and minutes (11).
Asking for just seconds will get you seconds, asking for seconds and days will give you just those. Asking just for days would give you the full number of days, so it would be 3.
Note that NSDateComponents can either represent a date (point time), or a time interval.
This flexibility gives you the ability to create some pretty cool time-based components.

NSDecimalNumber for finances

I'm building an app that deals with money and I've been using floating point arithmetic up until now, but I've learned that it's better to use NSDecimalNumber.
I want to make sure that I've understood it correctly, so here goes:
Imagine some worker, earning 20.57$/hour. This information is provided by the user. I did it like this before:
#property (nonatomic) float hourlyRate;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
NSNumber *hourlyRate = [numberFormatter numberFromString:self.rateTextField.text];
settingsObject.hourlyRate = [hourlyRate floatValue];
But I've now changed it to:
#property (nonatomic) NSDecimalNumber *hourlyRate;
settingsObject.hourlyRate = (NSDecimalNumber *)[NSDecimalNumber decimalNumberWithString:self.rateTextField.text locale:[NSLocale currentLocale]];
Is this the correct way to read NSDecimalNumbers from string?
Say this person enters a workplace at 10:01. I save that information like so:
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"start"];
Once the person is finished, the start time is read from NSUserDefaults like so:
NSDate *start = [[NSUserDefaults standardUserDefaults] objectForKey:#"start"];
The duration is calculated like so:
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:start] / 3600;
NSDecimalNumber *earned = [settingsObject.hourlyRate decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithFloat:interval]];
is this the correct and most efficient way, while keeping precision?
Thanks!
Is this the correct way to read NSDecimalNumbers from string?
Yes. However, you shouldn't need to cast the result. So it should just look like this:
settingsObject.hourlyRate = [NSDecimalNumber decimalNumberWithString:self.rateTextField.text locale:[NSLocale currentLocale]];
And the NSLocale part isn't necessary, unless you're using a non-current locale:
settingsObject.hourlyRate = [NSDecimalNumber decimalNumberWithString:self.rateTextField.text];
I don't think this function likes nil values, so you would want to make sure that rateTextField has a non-nil value first:
if ([self.rateTextField hasText]) {
settingsObject.hourlyRate = [NSDecimalNumber decimalNumberWithString:self.rateTextField.text];
}
else {
settingsObject.hourlyRate = [NSDecimalNumber zero];
}
is this the correct and most efficient way, while keeping precision?
Yes, your conversion of the interval to an NSDecimal number and then the multiplication looks good to me.
First you need an answer for this question:
How accurate do you want to be - or do you need to be?
Will your app generate invoices, or will it serve as the basis for invoices? If yes, you may have to stay away from floating point numbers. You may also have to think about how duration is actually used in calculations. There may be regulations for certain business areas or professions, which define how to measure / invoice time.
Not really accurate:
If you do not need to be really accurate, I would continue using floating numbers until you hit obstacles.
Accurate:
1. Money:
Store money as integers as cents.
2. Time:
Determine time slots and store them as integers (maybe minutes).
3. Calculations:
Calculate using integers. Never use floats.
Details:
When you have an input like 25.07 (I used a different number than your 20.57 to explain cents rendering) store it as 2507. Do your calculations in cents. For displaying convert to $ or $/hrs. For example:
int amount = 2507;
int amountDollars = amount / 100;
int amountCents = amount % 100;
NSString *output = [NSString stringWithFormat:#"%d.%02d $/hrs", amountDollars, amountCents];
NSLog(#"output = %#", output);
// prints:
// output = 25.07 $/hrs
For time chose a suitable base unit (minute / second / five minutes / ten minutes / half an hour?) and store that as an integer.
Lets assume you invoice in units of 10 minutes. You probably then bill the next 10 minutes, when they are begun. So if 11 minutes are in the record, you have to calculate 20 minutes. Similar issues exist for minutes - assume these values:
Actual Time | "Integer Time"
10:09:59 | 10:09
10:10:01 | 10:10
Difference:
00:00:02 | 00:01
If you just use actual time using floating points the first difference amounts to almost nothing - the second amounts to one minute. If your times are shown in the report as 10:09 and 10:10, people will wonder, why in the first case the amount is almost nothing.
Doing financial and time calculations is hard if you need to be really accurate. So it boils down to this: First find out, how accurate you need to be. (Note that "accurate" may have weird meanings and implications when entering the realm of regulations, laws etc.)

How would I be able to convert the date into an integer?

I need to be able to convert the date of the day to an integer so that I can then save it as an integer to use in other areas in my code. I know that there are other ways to save a date in Xcode, but for this specific problem I need to use it as an integer. So my over all question is how would I be able to convert the date into an integer so that I can then use that integer in an NSString? Thanks in advance!
You can do that by using the timeIntervalSinceReferenceDate method.
// Get time from baseline date to now as a double.
double interval = [[NSDate date] timeIntervalSinceReferenceDate];
// Re-apply the time value
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:interval];
Reference date is a base line date that will always have the same value. So you can safely use it as a reference point. Then you just store the NSTimeInterval (typedef to double) between the reference date and now. That gives you the number of seconds that has taken place between the reference date and now.
Edit:
As mentioned in the comments, if your date is eArlier than 2001, you can use the 1970 reference date.
// Get time from baseline date to now as a double.
double interval = [[NSDate date] timeIntervalSince1970];
// Re-apply the time value
NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval];
If your dates are later than 2001, either method will work for you.
You may convert from double to integer using
int interval = (int)[[NSDate date] timeIntervalSince1970];
Since the double will be truncated to the nearest second, you will want to decide if you want to round up or down. Leaving as is will round down. You can round to the proper nearest second by using:
interval = round(interval);

How to compare two dates in iOS [duplicate]

This question already has answers here:
iOS: Compare two dates
(6 answers)
Closed 9 years ago.
I want to compare two dates.This my code i wrote
NSDate *c_date=[NSDate date];
NSDate *newDate = [c_date dateByAddingTimeInterval:300];
This code is not working?What i am missing?
From NSDate, you can use
- (NSComparisonResult)compare:(NSDate *)anotherDate
You can use
- (NSComparisonResult)compare:(NSDate *)other;
which will yield a
typedef NS_ENUM(NSInteger, NSComparisonResult) {NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending};
in your example you're just creating two different NSDate objects with a known NSTimeInterval (300), so there is no comparison.
Use [NSDate timeIntervalSince1970] which will return a simple double value that can be used for comparison just like any other.
NSDate *c_date=[NSDate date];
NSDate *newDate = [c_date dateByAddingTimeInterval:300];
NSTimeInterval c_ti = [c_date timeIntervalSince1970];
NSTimeInterval new_ti = [newDate timeIntervalSince1970];
if (c_ti < new_ti) {
// c_date is before newDate
} else if (c_ti > new_ti) {
// c_date is after newDate
} else {
// c_date and newDate are the same
}
There are also the [NSDate compare:] method, that you might find more convenient.
Here's the thing (well, it might be the thing, it's not completely 100% clear from your question). NSDate represents an interval in seconds since 1st January 1970. Internally, it uses a floating point number (a double in OS X, not sure in iOS). This means that comparing two NSDates for equality is dry hit and miss, actually it's mostly miss.
If you want to make sure one date is within, say, 1/2 a second of another date, try:
fabs([firstDate timeIntervalSinceDate: secondDate]) < 0.5
If you just want both dates to be on the same day, you'll need to muck about with NSCalendar and date components.
See also this SO answer.
https://stackoverflow.com/a/6112384/169346

iPhone: How to get current milliseconds?

What is the best way to get the current system time milliseconds?
If you're looking at using this for relative timing (for example for games or animation) I'd rather use CACurrentMediaTime()
double CurrentTime = CACurrentMediaTime();
Which is the recommended way; NSDate draws from the networked synch-clock and will occasionally hiccup when re-synching it against the network.
It returns the current absolute time, in seconds.
If you want only the decimal part (often used when syncing animations),
let ct = CACurrentMediaTime().truncatingRemainder(dividingBy: 1)
[[NSDate date] timeIntervalSince1970];
It returns the number of seconds since epoch as a double. I'm almost sure you can access the milliseconds from the fractional part.
I benchmarked all the other answers on an iPhone 4S and iPad 3 (release builds). CACurrentMediaTime has the least overhead by a small margin. timeIntervalSince1970 is far slower than the others, probably due to NSDate instantiation overhead, though it may not matter for many use cases.
I'd recommend CACurrentMediaTime if you want the least overhead and don't mind adding the Quartz Framework dependency. Or gettimeofday if portability is a priority for you.
iPhone 4S
CACurrentMediaTime: 1.33 µs/call
gettimeofday: 1.38 µs/call
[NSDate timeIntervalSinceReferenceDate]: 1.45 µs/call
CFAbsoluteTimeGetCurrent: 1.48 µs/call
[[NSDate date] timeIntervalSince1970]: 4.93 µs/call
iPad 3
CACurrentMediaTime: 1.25 µs/call
gettimeofday: 1.33 µs/call
CFAbsoluteTimeGetCurrent: 1.34 µs/call
[NSDate timeIntervalSinceReferenceDate]: 1.37 µs/call
[[NSDate date] timeIntervalSince1970]: 3.47 µs/call
In Swift we can make a function and do as follows
func getCurrentMillis()->Int64{
return Int64(NSDate().timeIntervalSince1970 * 1000)
}
var currentTime = getCurrentMillis()
Though its working fine in Swift 3.0 but we can modify and use the Date class instead of NSDate in 3.0
Swift 3.0
func getCurrentMillis()->Int64 {
return Int64(Date().timeIntervalSince1970 * 1000)
}
var currentTime = getCurrentMillis()
To get milliseconds for current date.
Swift 4+:
func currentTimeInMilliSeconds()-> Int
{
let currentDate = Date()
let since1970 = currentDate.timeIntervalSince1970
return Int(since1970 * 1000)
}
So far I found gettimeofday a good solution on iOS (iPad), when you want to perform some interval evaluation (say, framerate, timing of a rendering frame...) :
#include <sys/time.h>
struct timeval time;
gettimeofday(&time, NULL);
long millis = (time.tv_sec * 1000) + (time.tv_usec / 1000);
Swift 2
let seconds = NSDate().timeIntervalSince1970
let milliseconds = seconds * 1000.0
Swift 3
let currentTimeInMiliseconds = Date().timeIntervalSince1970.milliseconds
It may be useful to know about CodeTimestamps, which provide a wrapper around mach-based timing functions. This gives you nanosecond-resolution timing data - 1000000x more precise than milliseconds. Yes, a million times more precise. (The prefixes are milli, micro, nano, each 1000x more precise than the last.) Even if you don't need CodeTimestamps, check out the code (it's open source) to see how they use mach to get the timing data. This would be useful when you need more precision and want a faster method call than the NSDate approach.
http://eng.pulse.me/line-by-line-speed-analysis-for-ios-apps/
// Timestamp after converting to milliseconds.
NSString * timeInMS = [NSString stringWithFormat:#"%lld", [#(floor([date timeIntervalSince1970] * 1000)) longLongValue]];
I needed a NSNumber object containing the exact result of [[NSDate date] timeIntervalSince1970]. Since this function was called many times and I didn't really need to create an NSDate object, performance was not great.
So to get the format that the original function was giving me, try this:
#include <sys/time.h>
struct timeval tv;
gettimeofday(&tv,NULL);
double perciseTimeStamp = tv.tv_sec + tv.tv_usec * 0.000001;
Which should give you the exact same result as [[NSDate date] timeIntervalSince1970]
CFAbsoluteTimeGetCurrent()
Absolute time is measured in seconds relative to the absolute reference date of Jan 1 2001 00:00:00 GMT. A positive value represents a date after the reference date, a negative value represents a date before it. For example, the absolute time -32940326 is equivalent to December 16th, 1999 at 17:54:34. Repeated calls to this function do not guarantee monotonically increasing results. The system time may decrease due to synchronization with external time references or due to an explicit user change of the clock.
This is basically the same answer as posted by #TristanLorach, just recoded for Swift 3:
/// Method to get Unix-style time (Java variant), i.e., time since 1970 in milliseconds. This
/// copied from here: http://stackoverflow.com/a/24655601/253938 and here:
/// http://stackoverflow.com/a/7885923/253938
/// (This should give good performance according to this:
/// http://stackoverflow.com/a/12020300/253938 )
///
/// Note that it is possible that multiple calls to this method and computing the difference may
/// occasionally give problematic results, like an apparently negative interval or a major jump
/// forward in time. This is because system time occasionally gets updated due to synchronization
/// with a time source on the network (maybe "leap second"), or user setting the clock.
public static func currentTimeMillis() -> Int64 {
var darwinTime : timeval = timeval(tv_sec: 0, tv_usec: 0)
gettimeofday(&darwinTime, nil)
return (Int64(darwinTime.tv_sec) * 1000) + Int64(darwinTime.tv_usec / 1000)
}
Try this :
NSDate * timestamp = [NSDate dateWithTimeIntervalSince1970:[[NSDate date] timeIntervalSince1970]];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"YYYY-MM-dd HH:mm:ss.SSS"];
NSString *newDateString = [dateFormatter stringFromDate:timestamp];
timestamp = (NSDate*)newDateString;
In this example, dateWithTimeIntervalSince1970 is used in combination of the formatter #"YYYY-MM-dd HH:mm:ss.SSS" that will return the date with year, month, day and the time with hours, minutes, seconds, and milliseconds. See the example : "2015-12-02 04:43:15.008". I used the NSString to be sure that the format will be has written before.
func currentmicrotimeTimeMillis() -> Int64{
let nowDoublevaluseis = NSDate().timeIntervalSince1970
return Int64(nowDoublevaluseis*1000)
}
let timeInMiliSecDate = Date()
let timeInMiliSec = Int (timeInMiliSecDate.timeIntervalSince1970 * 1000)
print(timeInMiliSec)
This is what I used for Swift
var date = NSDate()
let currentTime = Int64(date.timeIntervalSince1970 * 1000)
print("Time in milliseconds is \(currentTime)")
used this site to verify accuracy http://currentmillis.com/
NSTimeInterval time = ([[NSDate date] timeIntervalSince1970]); //double
long digits = (long)time; //first 10 digits
int decimalDigits = (int)(fmod(time, 1) * 1000); //3 missing digits
/*** long ***/
long timestamp = (digits * 1000) + decimalDigits;
/*** string ***/
NSString *timestampString = [NSString stringWithFormat:#"%ld%03d",digits ,decimalDigits];
[NSDate timeIntervalSinceReferenceDate] is another option, if you don't want to include the Quartz framework. It returns a double, representing seconds.

Resources