nil result from NSDateFormatter with 0's in format string - objective-c

I'm getting a date from a webservice back in the form MM00yyyy -- it is just the two-digit month, followed by two 0's, and then the four-digit year. When I do this:
NSString *expDate = #"12001975";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MM00yyyy"];
NSDate postDate = [dateFormat dateFromString:expDate];
[dateFormat dateFromString] returns nil for some reason. I have also tried MMddyyyy, and MM'0''0'yyyy, with no success either way. I am converting a similar date, except the 0's are actually the day with no problem using the same method.

To get this working, I would just use the following pattern MMHHyyyy. Since you need only the date and not neccessarily the hour, the HH will use the 00 to set the time as zeroth hour and hence you will get the date that you are looking for. Again this is just a hack and a workaround only to solve your current problem.

Have a look at the Date Formatting Guide from Apple. The section "Use Format Strings to Specify Custom Formats" lists all the different standards the are supported by various iOS versions for specifying a format string. I would say that "00" is not allowed, so that is the reason why "MM00yyyy" is failing. Similarly, "MMddyyyy" is also failing because no day can be "00".
I don't know if you can have more luck with UNIX functions, as the Apple doc suggests:
For date and times in a fixed, unlocalized format, that are always guaranteed to use the same calendar, it may sometimes be easier and more efficient to use the standard C library functions strptime_l and strftime_l.
Be aware that the C library also has the idea of a current locale. To guarantee a fixed date format, you should pass NULL as the loc parameter of these routines. This causes them to use the POSIX locale (also known as the C locale), which is equivalent to Cocoa's en_US_POSIX locale, as illustrated in this example.
struct tm sometime;
const char *formatString = "%Y-%m-%d %H:%M:%S %z";
(void) strptime_l("2005-07-01 12:00:00 -0700", formatString, &sometime, NULL);
NSLog(#"NSDate is %#", [NSDate dateWithTimeIntervalSince1970: mktime(&sometime)]);
// Output: NSDate is 2005-07-01 12:00:00 -0700

Getting the format strings right seems much more like art than science. I suggest you make a new string without the 00 in it and then have your DateFromatter process that with "MMyyyy".
While this might not be the "correct" way to do it, it should solve your problem pretty quickly.

The zeros are unsupported symbols. Apple supports the following characters for date formatting: http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns See the day section.

Related

Formatting NSDate

I am having some trouble comparing NSDate as they have a different format.
From one side I have a NSDate who looks like this:
2013-12-05T10:12:00.120Z
And from the other side I have another NSDate that looks this way:
2013-12-01 10:1200 +00000
My question is, how could I make the first NSDate look like the 2nd one?
And more important, what does 120Z mean? I guess it's the timezone, but I am not really sure of it.
By the way, is it there any way to can format the NSDate's and updating the time respecting the timezone hour difference?
Thanks a lot!
EDITED:
To get the 1st NSDate I do the following (I need to get the last opened date of a file):
MDItemRef item = MDItemCreate(NULL, (__bridge CFStringRef)filePath);
NSDate *date = (NSDate*)CFBridgingRelease(MDItemCopyAttribute(item,
kMDItemLastUsedDate));
And to get the 2nd NSDate I do the following:
NSDate* threeDaysAgo = [NSDate dateWithTimeIntervalSinceNow:-259200];
Convert both the dateStrings to NSDate and then you can easily compare the dateObjects.
For converting string to date thing you need :
NSDateFormatter
For comparing two dates :
resultant = [dateOne compare:dateTwo]
resultant can be NSOrderedAscending or NSOrderedSame or NSOrderedDescending.
You have a misunderstanding of what an NSDate is. It is not "in a format" at all, but is actually a wrapper around a a double which is the number of seconds since Jan 1st 1970 12:00am UTC. You can compare your two dates directly to see which one is the earlier. However, if you are trying to compare for equality, it's more tricky. If you want to see if they are within one minute of each other, you can do something like
[date1 timeIntervalSinceDate: date2] < 60.0;

Objective-C - How to Get Date Formatter to Add Colon in Time Zone Offset

I'm trying to format a date to match the format expected on the server side.
Wanted: 1985-01-24T00:00:00-07:00
Got: 1985-01-24T00:00:00-0700
Using: yyyy-MM-dd'T'HH:mm:ssZZZ
Is there a date format trick I can use to get that colon in there?
Here is my code. _birthdate is the date supplied by the birthdate selector:
NSDate *birthdate = (NSDate *)resultObject;
[_birthdate setNewTitle:[IRDate mmddyyFromNSDate:birthdate]];
//Set server-ready birthdate format
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZ"];
serverFormattedBirthDate = [formatter stringFromDate:birthdate];
NSLog(#"Birthdate: %#", serverFormattedBirthDate);
According to the Date Format Specifiers documentation, it looks like you'll need 5 Z's. That will get you things like "-08:00".
Aha, I see what you're getting at. If you run the formatting on OS X 10.8, you'll get the string you're expecting. However, if you run the formatting on iOS 5.1, you'll get the extra "GMT" in the string.
I'm guessing that the underlying data has changed in recent versions of the CLDR. In that case, I'm not sure what the correct answer is.

NSDateFormatter dateFromString returns incorrect date [duplicate]

This question already has answers here:
Get NSDate from NSDate adjusted with timezone
(2 answers)
Closed 9 years ago.
I am trying to use NSDateFormatter in my app which takes a date string and formats it to an NSDate so that I can do Date Comparisons, however I am finding when I use dateFromString and format it the date is losing one day.
NSString *dateString = #"02-06-2012";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSLog(#"My Date = %#", dateFromString);
[dateFormatter release];
This outputs to the console:
My Date = 2012-06-01 23:00:00 +0000
Try adding this lines to your code,
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT+0:00"]];
or
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
SWIFT update :
Code from quetion,
let dateString = "02-06-2012"
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
var dateFromString : NSDate = dateFormatter.dateFromString(dateString)!
println("My Date \(dateFromString)")
And Solution ,
dateFormatter.timeZone = NSTimeZone(name: "GMT")
OR
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00")
I don't believe that Dhruv's answer is correct. In fact, it's not clear there's any problem at all. You just seem to have an incorrect expectation of what should happen and/or interpretation of what's happening.
NSDate represents a moment in time. This moment does not have one unique name. It will be known by different names in different places and under different naming systems (time zones, calendars). NSDate doesn't deal with any of this, except lamely in its -description method, where it has to produce a string representation of that moment.
Second, a string like "02-06-2012" doesn't specify a precise moment in time. First of all, it's just a date with no time information, so NSDateFormatter just defaults to the first moment for that date. Second, it doesn't specify the time zone. The first moment of the calendar day is a different moment in each time zone. Unless you specify a time zone with -setTimeZone: or the string itself carries time zone information, NSDateFormatter assumes that any date strings you ask it to parse are in the current time zone.
So, your dateFromString object represents the first moment of the specified date, 02-06-2012, in your time zone. I expect this is what you wanted. However, you then got confused by the way that NSDate describes itself when logged. As I said, NSDate has to pick some "name" (string representation) for the moment it represents and which name it picks is fairly arbitrary. These days it is picking the name that the moment is known by in UTC. I gather from the log output shown in your question that you are located at UTC+0100. So, the date may look like it's one day earlier but it really is the same moment you specified. In other words, "2012-06-01 23:00:00 +0000" and "2012-06-02 00:00:00 +0100" are two equivalent names for exactly the same moment in time. You just aren't used to seeing the first one and misinterpreted it.
The lesson is that you have to stop relying on NSDate's self-description to be in any particular time zone. Really, you have to not rely on anything about it, since it's not documented. In fact, the docs for -[NSDate description] state, "The representation is not guaranteed to remain constant across different releases of the operating system."
Dhruv's solution seems to help merely because it causes NSDateFormatter and -[NSDate description] to agree on the time zone. But that's unreliable. It wouldn't work on Snow Leopard, for example, because -[NSDate description] used the local time zone instead of UTC in that version of the frameworks.
More importantly, though, it alters the actual moment represented by the NSDate object you get from NSDateFormatter's interpretation of your date string. I suspect you really want that to have a specific meaning – you want the string to be interpreted as being in the local time zone – and his solution thwarts your intent.
tl;dr: you were getting the date you wanted all along; don't rely on -[NSDate description]; don't use Dhruv's solution

NSDateFormatter crash. How come?

NSDateFormatter *timeFormatter = [[[NSDateFormatter alloc] init] autorelease];
[timeFormatter setDateFormat:#"h:mm a"];
NSString *fullTime = [timeFormatter stringFromDate:someDateHere];
NSArray *timeParts = [fullTime componentsSeparatedByString:#" "];
timeLabel.text = [timeParts objectAtIndex:0];
ampmLabel.text = [timeParts objectAtIndex:1];
The LAST line crashes with
NSRangeException*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]
How is this possible? There is a nil check on the date that returns just before this code.
From the Data Formatting Guide documentation (section Date Formatters > Use Format Strings to Specify Custom Formats > Fixed Formats):
Although in principle a format string specifies a fixed format, by default NSDateFormater still takes the user’s preferences (including the locale setting) into account.
...
In iOS, the user can override the default AM/PM versus 24-hour time setting. This may cause NSDateFormatter to rewrite the format string you set.
In other words, on an iOS device that's set for 24-hour time setting, you won't get "6:02 PM", you'll get "18:02", even though you specified "h:mm a". So when you separate that by spaces, you get back a single value, "18:02", not two values.
There's a caveat in the documentation for NSDateFormatter that says:
Note that although setting a format string (setDateFormat:) in principle specifies an exact format, in practice it may nevertheless also be overridden by a user’s preferences—see Data Formatting Guide for more details.
Could this apply in your case to produce a string without any spaces in it? (That would lead to a length 1 array when split by spaces, giving the exception you see in the place you see it.) Check this by logging the formatted date or attaching a debugger.
Note that the end of the page on date formats does recommend using plain old strftime_l when dealing with unlocalized dates/times. That might be more suitable for you. (Also, you want an AM/PM indicator in data that's bound for a computer? Seriously? The 24-hour clock is way easier to work with usually…)

using NSDate to find the DATE from string

I am having problem finding date from string that is formatted using NSDateFormatter
Now, I am using this code:
NSDate *afterDate=[NSDate dateWithNaturalLanguageString:balanceDateAfter.stringValue];
This code returning date with GeorgianCalendar format but I want it in PersianCalendar.
I think if I use this code :
NSDate *afterDate=[NSDate dateWithNaturalLanguageString:balanceDateAfter.stringValue locale:];
It will return true date format but I don't know how can I use locale to set appropriate date formatter ( or my system locale ).
balanceDateAfter in above codes is an NSTextfield with NSDateFormatter.
NSDates do not have a calendar. An NSDate represents an absolute moment in time as defined by the difference between that moment and the first instant of 1st January 2001 in GMT. Basically, it's a positive or negative number of seconds, nothing more.
If you have an appropriate formatter assigned to the text field, you should get its value using -objectValue, not -stringValue. That way, you will be given the NSDate directly and you won't need to parse the string yourself.