NSDateComponentsFormatter NSString to NSTimeInterval - ios

I hope I didn't miss anything but from reading the documentation I get:
NSDateComponentsFormatter provides a method - (NSString * nullable)stringFromTimeInterval:(NSTimeInterval)ti which can be used to convert an NSTimeInterval into an NSString.
However I couldn't find any method that that converts the resulting string back into an NSTimeInterval.
Is their anything like an equivalent to NSDateFormatter - (NSDate *)dateFromString:(NSString *)string ?
Thanks in advance!

NSTimeInterval is simply a double value, so just get the doubleValue of the string.
NSTimeInterval ti = [yourString doubleValue];
EDIT: Per your comments, you are correct- I was making an assumption that the value returned by stringFromTimeInterval: was an unformatted double value. Based off some quick observations, there does not seem to be a simple way to convert the string back to a double value, regardless of the unitsStyle used in the NSDateComponentsFormatter, as none of the styles provide an easily-parseable format. I assume you would need to write your own method to search through the resulting string for ranges of substrings and do the math yourself.

Related

Storing dates in CoreData - Convert date string to NSTimeInterval?

So I want to store dates in my CoreData entity and the model indicates the field should be of NSTimeInterval. Not sure why it's not NSDate though as NSTimeInterval sounds... odd.
From my JSON data source I have the following string: "2016-01-28T23:20:00" and I have no idea how to convert this to a NSTimeInterval. I can convert it to NSDate once I figure out the correct format, but that doesnt do much me much good.
Thanks!
You can store NSDate in CoreData Directly.
Update:
If you are using scalar propertie, convert like this:
// `NSTimeInterval` --> `NSDate`:
var date = NSDate(timeIntervalSinceReferenceDate: 123)
// `NSDate` --> `NSTimeInterval`:
var timeInterval = date.timeIntervalSinceReferenceDate

Core Data NSTimeInterval using an accessor directly is buggy

I'm setting an NSTimeInterval using setValueForKey within an NSManagedObject Subclass, the value gets set correctly, and is also correct when it is retrieved using valueForKey, however, if an accessor is used directly, it returns an incorrect value. Here is a code sample that demonstrates the issue
let date = NSDate() //NSTimeIntervalSince1970 = 1447054145.15281
self.setValueForKey(date, "dateLastSynced")
self.valueForKey("dateLastSynced") //= 1447054145.15281
self.dateLastSynced // !!ERROR Incorrect value = 468746945.152815
Strangely enough, if the dateLastSynced is converted to an NSDate, everything works perfectly.
Any ideas on whats happening?
A scalar property of type NSTimeInterval for a Core Data Date
property represents the time in seconds since the reference date
Jan 1, 2001. The Core Data generated accessor methods transparently
convert between NSTimeInterval and NSDate.
Therefore you set a value using the scalar accessor with
obj.dateLastSynced = date.timeIntervalSinceReferenceDate
and you retrieve the value with
let date = NSDate(timeIntervalSinceReferenceDate: obj.dateLastSynced)
This gives the same results as the Key-Value Coding methods
// Set:
obj.setValueForKey(date, "dateLastSynced")
// Get:
let date = obj.valueForKey("dateLastSynced")
Assigning to self.valueForKey("dateLastSynced") won't work; it's not an lvalue. You need to use setValueForKey.
Also, if the dateLastSynced is a date property, you cannot assign it a double value and expect it to work. Use
self.setValue(NSDate(timeIntervalSinceReferenceDate: <value>), forKey:"dateLastSynced")

set nslocale for number part of nsstring

Is there any way to set locale on number part of string ?
like if nsstring is like this : "0.510.220" it shows this inside
uilabel view : "۰.۵۱۰.۲۲۰"
i know i can change the nslocale with this if number are valid :
NSDecimalNumber *someNumber = [NSDecimalNumber decimalNumberWithString:#"123"];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
NSLocale *gbLocale = [[[NSLocale alloc] initWithLocaleIdentifier:#"ar"] autorelease];
[formatter setLocale:gbLocale];
but how can i make that happen on full nsstring text? like number inside
string.also im want to make this happen on +7.0 sdk.
No, because what you want is not something that a locale does. "۰.۵۱۰.۲۲۰" is not "0.510.220" in a different locale, it's just simply a different string.
Strings don't have locales. They consist of characters. A string with the characters "0.510.220" has those characters, not others. The Arabic digits are different characters and so you'd need a string with different content.
An NSNumberFormatter is not applying a locale to a string. It's applying a locale to the conversion from a number to a string. That's completely different from what you seem to want.
You could try to parse your string to find a substring that appears to be a number, convert that substring to an actual number using one NSNumberFormatter in one locale, convert the resulting number back to a string using a second NSNumberFormatter in a different locale, and construct a new string by replacing the original substring with the new string.

Displaying two different types of variables in one label string

I am trying to make a CCLabelTTF display a string and an integer together. Like this:
Your score is 0.
I've tried a few things but I usually get the warning Data argument not used by format string, and the label doesn't output the correct statements.
I am just trying to figure out the format in which to put these in and searching Google hasn't provided much, as I'm not really sure what exactly to search.
I've tried
label.string = (#"%#", #"hi", #"%d", investmentsPurchased);
but obviously that isn't correct. How would I do this?
Thanks.
(I assume this is ObjC and not Swift.) Try something like this:
label.string = [NSString stringWithFormat:#"hi %d", investmentsPurchased];
You use a single format string, which contains static text and replacement tokens (like %d) for any replacement variables. Then follows the list of values to substitute in. You can use multiple variables like:
label.string = [NSString stringWithFormat:#"number %d and a string %#", someInteger, someString];
use NSString newString = [NSString stringWithFormat:#"hello %#", investmentsPurchased];
in short: use stringWithFormat

Performing arithmetic on double

I have an app whose purpose is to compare chronologically ordered time intervals, which are stored by Core Data (via MagicalRecord) as attributes of type double, on an entity called TimedActivity. Ordering directions are supplied by attributes called activityOfInterest and benchmarkActivity on another entity named SearchSpecs. The scheme may seem a bit overcomplicated since I'm pretty green, but that part of it works.
The problem is that getting percentages from two doubles appears to be a bit of a runaround, at least according to the research I've done. I don't need extreme precision. Round seconds are fine. I found a suggestion relating to the use of NSDecimalNumber, but it too seemed like a long way around the corner.
Here is the relevant code in it's current state, with pseudocode to indicate my problem area:
#pragma mark - Go button case handlers
-(void) handleAvsAAction
{
// NSArray *searchSpecsObjects = [SearchSpecs MR_findAll];
// NSLog(#"SearchSpecs number of objects is %i",[searchSpecsObjects count]);
NSArray *searchSpecsArray = [SearchSpecs MR_findAll];
NSLog(#"searchSpecsArray count is %i", [searchSpecsArray count]);
SearchSpecs *thisSpec = [searchSpecsArray objectAtIndex:0];
NSLog(#"SearchSpec activityOfInterest should be %#", thisSpec.activityOfInterest);
NSLog(#"SearchSpec benchmarkActivity should be %#", thisSpec.benchmarkActivity);
// NSArray *activityOfInterestArray;
// NSArray *benchmarkActivityArray;
NSNumber *activityOfInterestDurationTotal;
NSNumber *benchmarkActivityDurationTotal;
NSPredicate *activityOfInterestPredicate = [NSPredicate predicateWithFormat:#"name == '%#'",thisSpec.activityOfInterest];
NSPredicate *benchmarkActivityPredicate = [NSPredicate predicateWithFormat:#"name == '%#'", thisSpec.benchmarkActivity];
activityOfInterestDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:activityOfInterestPredicate];
NSLog(#"The sum of all the durations for the activity of interest is %zd", activityOfInterestDurationTotal);
benchmarkActivityDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:benchmarkActivityPredicate];
NSLog(#"The sum of all the durations for the benchmark activity is %zd", benchmarkActivityDurationTotal);
[self doTheMathAvsA];
}
-(void) doTheMathAvsA
{
// Get the total and respective percentages of the totalled durations from the criteria distilled in handleAvsAAction
NSNumber *total;
total = (activityOfInterestDurationTotal + benchmarkActivityDurationTotal);
}
Edit: modified doTheMathAvsA to clarify the desired result.
All help or suggestions appreciated!
Second edit:
OK, your answer below makes sense, and thanks #Martin R!
However, the two quantities in question here originate as NSTimeIntervals, and as mentioned above, are stored as attributes of type double, on an entity called TimedActivity.
So, it seemed rational to me to slightly rewrite the code to extract them from the persistent store as NSTimeIntervals, which I am assured are really just doubles. However, when I do this, I get this error:
Assigning to 'NSTimeInterval' (aka 'double') from incompatible type 'NSNumber *'
Here are the modified declarations:
NSTimeInterval activityOfInterestDurationTotal;
NSTimeInterval benchmarkActivityDurationTotal;
And here's where the error appears:
activityOfInterestDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:activityOfInterestPredicate];
NSLog(#"The sum of all the durations for the activity of interest is %#", activityOfInterestDurationTotal);
benchmarkActivityDurationTotal = [TimedActivity MR_aggregateOperation:#"sum:" onAttribute:#"duration" withPredicate:benchmarkActivityPredicate];
NSLog(#"The sum of all the durations for the benchmark activity is %#", benchmarkActivityDurationTotal);
OK, I assume that the NSNumber referred to in the error message is this property in the TimedActivity managed object subclass, auto-generated from the data model:
#property (nonatomic, retain) NSNumber * duration;
So my question becomes:
Is it really necessary to resort to such seemingly ever-widening circles of conversion and retro-conversion to perform such a seemingly simple calculation? Or am I missing a more straightforward solution?
Thanks!
You cannot perform arithmetic directly on NSNumber objects. The easiest solution is
to convert them to double for the addition:
double tmp = [activityOfInterestDurationTotal doubleValue] + [benchmarkActivityDurationTotal doubleValue];
and the result back to NSNumber, if necessary:
NSNumber *total = #(tmp);
Update: By default, the Xcode generated accessor methods use Objective-C objects even
for primitive Core Data types such as "Double". You can change that by selecting the
"Use scalar properties for primitive data types" option when creating the subclass files.
Then a "Double" property is declared as
#property (nonatomic) double activityOfInterestDurationTotal;
and you can access it "directly" as for example
NSTimeInterval duration = thisActivity.duration;
because NSTimeInterval is just another name for double.
But there is another problem: The MagicalRecord "convenience method" MR_aggregateOperation: uses a special fetch request with NSDictionaryResultType to
fetch the sum of all duration values. And even if you chose to use a scalar property
for the duration, the result of MR_aggregateOperation: is always some Objective-C object, in this case NSNumber, there is no way around it.
So the only way to avoid a conversion between NSNumber and double would be to use a scalar
property as described above, and instead of using MR_aggregateOperation:, fetch all
objects and add the duration values yourself in a simple loop.
But note that the fetch request with the aggregate operation performs the calculations
on the SQLite level, this is probably more effective then actually fetching all objects.

Resources