Check if string is in format dd.mm.yyyy - objective-c

I wanna check if a string is in format dd.mm.yyyy, like
if(myString is in format dd.mm.yyyy) {
NSLog(#"Ok");
}
else{
NSLog(#"No");

You can use a code like this:
NSString *dateString = #"01.01.1970";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"dd.MM.yyyy";
if ([dateFormatter dateFromString:dateString]) {
//YES
}
Why NSDateFormatter: it was created to parse dates. Plus, this way you get an easy way to change date format and as a side effect, get a valid NSDate object that you can work with.
However, if you are intending to use this dateFormatter often (for instance, it is used inside a UITableViewCell), you might encounter performance issues. If you did, and you're sure that NSDateFormatter is what is causing it (Instruments might help you here), you could reuse your dateFormatter. For example, like so:
NSString *dateString = #"01.01.1970";
static NSDateFormatter *dateFormatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"dd.MM.yyyy";
});
if ([dateFormatter dateFromString:dateString]) {
//YES
}
It seems (it is my guess based on tests that I ran) that the first call to dateFromString triggers lazy initialization inside the dateFormatter, and it takes some time (several tests results are below). If you reuse it, the NSDateFormatter initialization is performed only once.
On my iPhone 5S with iOS 8.4.1 the dispatch_once version works about 10 times faster:
dispatch_once: 0.536 seconds, recreation: 5.475 seconds
(time to parse 10.000 dates)
In the same test #zaph got a 2x performance difference on his iPhone 6S with iOS 9.x:
dispatch_once: 0.57 seconds, recreation: 1.01 seconds
(time to parse 10.000 dates)
So, it depends on the device, the OS version and on how intensively you're going to use that dateFormatter. In some cases the second code fragment might be an overkill. But I encountered situations where it provided a noticeable performance boost.
UPD: Also note that quite often American dates are also written with a dot as a separator, so what seems to be a dd.MM.yyyy date might actually be a MM.dd.yyyy date (e.g. April 5th instead of May 4th). For dates with dd > 12 it's not an issue, but otherwise it is. I don't think there's anything you could do about that without an additional context though, so just be warned.

You can using Regex to check it.
For example this code using Regex to check "mm.dd.yyyy":
NSError *error = NULL;
NSString *expForreg = #"^((((0[13578])|([13578])|(1[02]))[\\.](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\\.](([1-9])|([0-2][0-9])|(30)))|((2|02)[\\.](([1-9])|([0-2][0-9]))))[\\.]\\d{4}$|^\\d{4}$";
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:expForreg
options:NSRegularExpressionCaseInsensitive
error:&error];
NSArray *matches = [regex matchesInString:#"10.30.1989" options:0 range:NSMakeRange(0, [#"10.30.1989" length])];
if(matches && matches.count > 0)
{
NSLog(#"Ok");
}else
{
NSLog(#"No");
}
Hope this help!

You can use a regular expression:
NSString *testString = #"11.22.3333";
NSString *pattern = #"^\\d{2}\\.\\d{2}\\.\\d{4}$";
NSRange range = [testString rangeOfString:pattern options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
NSLog(#"Ok");
}
else{
NSLog(#"No");
}
Bit that is not really a good date test.

Related

compare two dates in objective-c

I am sure this question came up before I am pulling my hair out. I have two dates - one from an Object on Parse.com and the other one local. I try to determine whether the remote object has been updated so that I can trigger actions locally.
When looking at the NSDate of both objects they seem identical but a comparison reveals that the remote object is newer - when checking the time internal (since1970) it becomes obvious that there is a difference but why? When I first created the local object all I did was
localObject.updatedAt = remoteObject.updatedAt //both NSDate
But when looking closer I get this:
Local Time Interval: 1411175940.000000
Local Time: 2014-09-20 01:19:00 +0000
Remote Time Interval: 1411175940.168000
Remote Time: 2014-09-20 01:19:00 +0000
Does anyone have an idea why that is and whether I can ignore this detail? Does iOS round up or something?
Adding more code:
#property (strong, nonatomic) NSDate *date;
...
PFQuery *query = [PFObject query];
[query whereKey:#"Product" equalTo:#"123456"]
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
self.date = objects[0].updatedAt;
NSTimeInterval localTime = [self.date timeIntervalSince1970];
NSTimeInterval remoteTime = [objects[0].updatedAt timeIntervalSince1970];
NSLog(#"Local Time Interval: %f", localTime);
NSLog(#"Local Time: %#", self.date);
NSLog(#"Remote Time Interval: %f", remoteTime);
NSLog(#"Remote Time: %#", objects[0].updatedAt);
}
else
{
NSLog(#"Error with query");
}
}];
That results in the console output above - and I don't understand why these dates are different.
I cannot explain why there is a difference, but the important thing to understand is that there can be a difference and that when comparing dates you have to use a tolerance value.
The Apple Date and Time Programming Guide has an example of how to compare two dates within a given tolerance:
To compare dates, you can use the isEqualToDate:, compare:,
laterDate:, and earlierDate: methods. These methods perform exact
comparisons, which means they detect sub-second differences between
dates. You may want to compare dates with a less fine granularity. For
example, you may want to consider two dates equal if they are within a
minute of each other. If this is the case, use timeIntervalSinceDate:
to compare the two dates. The following code fragment shows how to use
timeIntervalSinceDate: to see if two dates are within one minute (60
seconds) of each other.
if (fabs([date2 timeIntervalSinceDate:date1]) < 60) ...
It's up to you decide on the tolerance value, but something like 0.5 seconds seems reasonable:
+ (BOOL)date:(NSDate *)date1
equalsDate:(NSDate *)date2
{
return fabs([date2 timeIntervalSinceDate:date1]) < 0.5;
}
Parse stores dates as iso8601 format. This makes things very complex as Apple does not manage the format well. While the idea of the standard is awesome, until everyone plays by the same rules, anarchy rules..
I convert everything inbound from parse into usable format before attempting anything on their date time values..
Drop this into a library somewhere, and save yourself tons of headaches. This took weeks of searching and scratching to overcome.
+ (NSDate *)convertParseDate:(NSDate *)sourceDate {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
NSString *input = (NSString *)sourceDate;
dateFormatter.dateFormat = #"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
// Always use this locale when parsing fixed format date strings
NSLocale* posix = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
dateFormatter.locale = posix;
NSDate *convertedDate = [dateFormatter dateFromString:input];
assert(convertedDate != nil);
return convertedDate;
}

iTunes Search API, finding Free prices

When searching the iTunes store, I've hit a little problem. I'm trying to change the text of my label to "FREE" when the price is 0.00, as opposed to displaying the price. The problem is, my comparison of the two NSDecimalNumbers fails. Here's where I am currently at.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatter setCurrencyCode:self.searchResult.currency];
NSString *price = [formatter stringFromNumber:self.searchResult.price];
NSDecimalNumber *free = [[NSDecimalNumber alloc] initWithFloat:0.00f];
NSLog(#"Price:%#",price);
NSLog(#"Free:%#",free);
NSLog(#"self.searchResult.price: %#", self.searchResult.price);
if (self.searchResult.price == free) {
NSString *freeText = [NSString stringWithFormat:#"FREE"];
self.priceLabel.text = freeText;
}
else {
self.priceLabel.text = price;
}
NSLog(#"priceLabel:%#", self.priceLabel.text);
What's really weird is that the Console even says that both free and del.searchResult.price are the same:
2012-11-24 20:01:16.178 StoreSearch[1987:c07] Price:$0.00
2012-11-24 20:01:16.178 StoreSearch[1987:c07] Free:0
2012-11-24 20:01:16.178 StoreSearch[1987:c07] self.searchResult.price: 0
2012-11-24 20:01:16.179 StoreSearch[1987:c07] priceLabel:$0.00
I'm a little confused by this to be frank. Any help would be appreciated. If you could explain why this has happened so that I can learn not to do it again, then I'd be even more grateful!
Regards,
Mike
you got NSNumber and another NSNumber (NSDecimalNumber) and you do a pointer equal check you either need need to call isEqual or compare the primitive float values
== with objects doesnt compare the value but the object pointer (the memory address)
if(searchResult.price.floatValue == free.floatValue)
note that a float is inprecise and generally should not be used for any calculation or comparison. It is ok in this case though

Getting an NSDate via NSDateFormatter from a string of unknown format

I know there are many NSDateFormatter questions on here, so if I duplicate, I'm sorry. I just couldn't find anything that was quite what Im asking.
From all the questions here on SO, I have come to the conclusion that -[NSDateFormatter dateFromString:] will always return NULL if your formatter object doesn't have the correct date format. How do you get a date from a string if you don't know the format? I'm trying to get a date from a UITextField.
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setLenient:YES];
NSDate *tempDate = [formatter dateFromString:self.birthdayTxtfld.text];
self.currentCustomer.birthday = ([self.birthdayTxtfld.text isEqualToString:#""]) ? NULL : tempDate;
[formatter release];
tempDate is always NULL.
I think your taking the wrong approach. I would on the other hand restrict and format the UITextField so the user has to enter the date in a specific format. Or just use a date picker. There are just way too may different inputs the user could give you.
Or you can read through this: NSDate
Another option is to create a list of accepted date formats:
#define DATEFORMATS #[#"MM/dd/yyyy", #"MM/dd/yy",...
Then Have a method that you pass the date string to and check if you can format it:
+ (NSDateFormatter*)getDateFormat:(NSString*)dateString {
NSArray *dateFormats = DATEFORMATS;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSDate *date = nil;
for (NSString *dateFormat in dateFormats) {
[formatter setDateFormat:dateFormat];
date = [formatter dateFromString:dateString];
if (date) {
return formatter;
}
}
return nil;
}
If you get nil its not a date or its in a format you don't support. Otherwise you will have the correct format you need. You can switch this around to return the date instead of the format. I have it this way because I needed the format not the date for a project.
While I'm in agreement with #Jaybit that you probably need to ditch the text box and use a better input, the answer to this specific question lies in some crafty string parsing. Whenever you are doing string parsing, RegEx is your friend. Web developers end up having to do this crap all the time. This example is in JavaScript, but the RegEx ought to be portable enough that it works in ObjC:
http://www.codingoptimist.com/2009/07/using-javascript-and-regex-to-parse.html
You can do this with RegExKit or NSRegularExpression

What's the simplest way to parse RFC3339 date string in iOS?

Youtube API returns date string in RFC3339 format. I found how to parse it on manual, anyway, this is too long.
- (NSString *)userVisibleDateTimeStringForRFC3339DateTimeString:(NSString *)rfc3339DateTimeString
// Returns a user-visible date time string that corresponds to the
// specified RFC 3339 date time string. Note that this does not handle
// all possible RFC 3339 date time strings, just one of the most common
// styles.
{
NSString * userVisibleDateTimeString;
NSDateFormatter * rfc3339DateFormatter;
NSLocale * enUSPOSIXLocale;
NSDate * date;
NSDateFormatter * userVisibleDateFormatter;
userVisibleDateTimeString = nil;
// Convert the RFC 3339 date time string to an NSDate.
rfc3339DateFormatter = [[[NSDateFormatter alloc] init] autorelease];
enUSPOSIXLocale = [[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] autorelease];
[rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[rfc3339DateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
[rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
if (date != nil) {
// Convert the NSDate to a user-visible date string.
userVisibleDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
assert(userVisibleDateFormatter != nil);
[userVisibleDateFormatter setDateStyle:NSDateFormatterShortStyle];
[userVisibleDateFormatter setTimeStyle:NSDateFormatterShortStyle];
userVisibleDateTimeString = [userVisibleDateFormatter stringFromDate:date];
}
return userVisibleDateTimeString;
}
I can make a function contains this, but I want to know is there pre-defined way on Cocoa foundations or standard C or POSIX library to do this. And I want to use it if there it is. Can you let me know is there more simpler way? Or It will be very appreciate if you confirm this is most simple way :)
The pure stuff-that-comes-with-Cocoa way is exactly what you're doing. You can make this method both shorter and faster by creating the date formatters elsewhere, probably in init, and using/reusing them in this method.
You need two formats because fractional seconds are optional, and the timezone should be Z5, not Z. So you create two formatters with formats
#"yyyy'-'MM'-'dd'T'HH':'mm':'ssX5"
#"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSSSSX5"
and try them both. That's obviously for RFC3339; your strings might not be in that format. Glad you didn't ask for RFC822 which is a pain to do correctly. But you should really have a method first that returns NSDate, because most uses don't actually need a string formatted for the user.
I had some problems with parsing RFC 3339 in Obj-c since the fractional seconds and zone seems to be optional.
The most reliable function that I found was this Gist (of which I am not the author): https://gist.github.com/mwaterfall/953664

How to format this NSString correctly?

I want to format a string that can look like that:
0.0580 which means 5.8 ct
0.1580 which means 15.8 ct
1.1580 which means 1.15 €
So the string can be anything in x.xxxx format. Now I started formating it but I am new to objective-c and iOS.
First I want to remove the last character because the last number does not really matter and I don't want to round numbers.
NSString *responseString = [responseData
substringWithRange:NSMakeRange(1,
[responseData length]-2)];
This gives me x.xxx so far. Any idea how to proceed and what code to use? Are there any libraries on that?
Take a look at the NSNumberFormatter class. It should do what you need. Something like this:
NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init];
NSNumber *myNumber = [NSNumber numberWithDouble:[#"0.158" doubleValue]];
[numFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *formattedValue = [numFormatter stringFromNumber:myNumber];
[numFormatter release];
Also look at NSNumberFormatterStyle and NSNumberFormatterBehavior to control the format.
Once you have your number in the form x.xxx, you could do something like:
float floatValue = [#"0.158" floatValue]; // Get your string as a number.
floatValue *= 100; // Turn '0.158' into '1.58'
Does this answer your question? I'm not quite sure that it does, so update your question and I will try to assist you better.