objective-c - NSDateFormatter returns wrong date - iphone

I have this piece of code:
// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MMMM d, YYYY"];
NSDate *formatDate = [dateFormat dateFromString:self.date];
NSLog(#"1-%#", self.date);
NSLog(#"2-%#", formatDate);
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:formatDate];
NSString *dateCal = [NSString stringWithFormat:#"%d/%d/%d", [components day], [components month], [components year]];
NSLog(#"3-%#", dateCal);
milage.date = dateCal;
The first NSLog returns:
1-March 23, 2012
The second:
2-2011-12-25 00:00:00 +0000
The third:
3-25/12/2011
Why does the date change when getting the date from the string and formatting it? I'm expecting the third NSLog (or dateCal) to equal 23/3/2012. I live in the UK so its not to do with the timezone..
Thanks,
Jack

Needed to use lower case 'y' in the line:
[dateFormat setDateFormat:#"MMMM d, YYYY"];

Have you used the setLocale method?
Also, from the technical Q&A:
If you're working with user-visible dates, you should avoid setting a date format string because it's very hard to predict how your format string will be expressed in all possible user configurations. Rather, you should try and limit yourself to setting date and time styles (via -[NSDateFormatter setDateStyle:] and -[NSDateFormatter setTimeStyle:]).

Use [dateFormat setDateStyle:NSDateFormatterLongStyle];
Instead of [dateFormat setDateFormat:#"MMMM d, YYYY"];
Will give you reason as soon as I find it.

Related

NSDate wrong output when add day to NSDate

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];
NSLog(#"%#",dateString);
// Retrieve NSDate instance from stringified date presentation
NSDate *dateFromString = [dateFormatter dateFromString:dateString];
// Create and initialize date component instance
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setDay:2];
// Retrieve date with increased days count
NSDate *newDate = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:dateFromString options:0];
NSLog(#"Original date: %#", [dateFormatter stringFromDate:dateFromString]);
NSLog(#"New date: %#", [dateFormatter stringFromDate:newDate]);
OutPut
2013-05-17
Original date: 2013-05-17
New date: 1412647-09-06
I add 2 day to that. The new date should be "2013-05-19?. Can anyone tell me what I wrong? Thank in advance.
I assume that you forgot to initialize the day variable. If you add
NSUInteger day = 2;
then your code produces the expected result in my test program.
The init methode of NSDateComponents does not initializes the components. Thus, e.g., year is undefined. Form Apple's documentation:
An instance of NSDateComponents is not responsible for answering questions about a date beyond the
information with which it was initialized. For example, if you initialize one with May 6, 2004,
its weekday is NSUndefinedDateComponent

How To Get The Current Date From Device?

I am facing a weird problem with NSDate, when I try fetch a date from device, sometimes it shows previous month for some versions
Here is my chunk of code for reference
NSDate *date = [NSDate date];
NSDateFormatter *dateF = [[NSDateFormatter alloc]init];
[dateF setDateFormat:#" dd.MM.yyyy "];
NSString *selectedDate = [dateF stringFromDate:date];
Any inputs are appreciated, Thank you
To avoid later localizing problems you might use NSCalendar and its method components:fromDate:
Something like this:
NSCalendar * calendar = [NSCalendar currentCalendar];
NSDateComponents * components = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:[NSDate date]];
NSString * stringDate = [NSString stringWithFormat:#"%d.%d.%d", components.day, components.month, components.year];
NSDate *today = [NSDate date];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"hh:mma dd/MMM"];
NSString *dateString = [dateFormat stringFromDate:today];
NSLog(#"date: %#", dateString);
[dateFormat release];
This is an example by Apple so it looks like you have your upper-case / lower-case right
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd 'at' HH:mm"];
Are you sure your device's date is set right? Also have you tried setting the locale of the NSDateFormatter?
EDIT:
To address you question in comments: NSDate is a point in time irrespective of time zones, calendars and so so on. NSCalendar and NSDateFormatter allow you to convert this point in time into a representation that is correct in a given time zone, with a given calendar.

NSDate is converting really strangely

I have a time: 7:46 am
I want to convert this to NSDate. I do this:
NSDateFormatter *f = [NSDateFormatter new];
[f setDateFormat:#"h:mm a"];
NSDate *sr = [f dateFromString:#"7:46 am"];
I NSLog sr and I get 1969-12-31 22:46:00 +0000
Those times are not the same. Why is this so messed up?
No. Its not strange. NSDateConverter & NSDate are just doing their intended job here.
You are trying to convert "7:46 am" into a date. It contains only the time. No date is specified in the string. NSDate will default to "1970-01-01"(Unix epoch) if no date is specified. So after you convert the string you will get the date "1970-01-01 7:46 am". When you trying to display this in NSLog, if will display the date after adjusting the timeZone offset value. I guess you live in Japan or Korea. Probably the offset of your region is +09:00. So it diaplays the date subtracting the offset. So you are seeing "1969-12-31 22:46:00 +0000" in the log.
You can use the following method to set that time to a particular date, may be today.
NSString *timeStr = #"7:46 am";
NSDateFormatter *f = [NSDateFormatter new];
[f setDateFormat:#"yyyy-MM-dd"];
NSString *dateStr = [f stringFromDate:[NSDate date]]; // dateStr = 2011-06-10
dateStr = [dateStr stringByAppendingFormat:#" %#", timeStr]; // dateStr = 2011-06-10 7:46 am
[f setDateFormat:#"yyyy-MM-dd h:mm a"];
NSDate *sr = [f dateFromString:dateStr];
You aren't providing the day or the timezone... assuming you want to express "today at 7:42am", you can use this code:
NSDate *currentDate = [NSDate date];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setHour:7];
[comps setMinute:42];
NSDate *myDate = [calendar dateByAddingComponents:comps toDate:currentDate options:0];
[comps release];
The NSLog of myDate should give you the expected output now (assuming you wanted today#7:46am).
Since you are only specifying the time that you want the NSDate to refer to, and not the date, the formatter is using the default date (which seems to be very close to the UNIX epoch). Like Julio said, you should specify the current date as well, if you want the NSDate to refer to the time on that specific date.

Comparing NSDates to determine day or night?

I'm parsing a weather XML that gives me the sunrise + sunset times for the user's location. I've parsed them as strings, and they look like this: 7:20 am and 5:34 pm, for example.
I then converted these two times into an NSDate by doing this:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"hh:mm a"];
NSDate *Sunrise = [dateFormat dateFromString:sunrise];
NSDate *Sunset = [dateFormat dateFromString:sunset];
NSDate *today = [NSDate date];
[dateFormat release];
Now I have three dates which I now want to compare to determine whether the current time is night or day. The problem is, when I NSLog the Sunrise and Sunset times I see that the year is 1970 on both the dates that came from strings. I don't know where to start on how to compare the dates. Any ideas?
Theres actually a pretty simple way to do this. NSDateFormatter has a method called setDefaultDate: which basically uses a given date object to fill in any fields not included by the date format string. So, using the variables from your sample:
[dateFormat setDefaultDate:today];
Just put this line before the calls to dateFromString:, and you should be good to go.
Reference: NSDateFormatter Class Reference
You may split up a NSDate into Date Components, you'll need a NSCalendar Object and tell it to give you a NSDateComponents Instance for your date.
Like so:
NSCalendar *gregorian = [NSCalendar currentCalendar];
NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDate *date = [NSDate date];
NSDateComponents *comps = [gregorian components:unitFlags fromDate:date];
NSLog(#"Parts: Day %d, Month %d, Year %d", [comps day], [comps month], [comps year]);
Instead of the example "unitFlags" you may OR together any of the NS*CalenderUnit Flags to get the corresponding elements into "comps". In your case it would be something like NSHourCalenderUnit | NSMinuteCalenderUnit .
Try altering your sunrise and sunset NSString variables to contain the current date. Something like "2010-12-15 7:20am". Once you parse that, your Sunrise and Sunset dates will be correct, and the comparison should be easy.

objective c and NSDate

I am looking for component that can handle a spesific date.
what i am trying to do is to get Astring fron sever that represent date(for example 04-08-2012) in my iphone i want to be able to "work" with this date. such to compare it to another date , check if the date in the past or future and to print it to the app GUI
i tried work with NSDate but i didnt found how can i set a spesific date?
thanks
You can use an NSDateFormatter
Here is a sample code to parse a date from string:
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:#"%A, %B %d, %Y"];
NSDate* date = [formatter dateFromString:aString];
[date compare:anotherDate];
More about Date Formatter here
The date format string is composed of various elements that pull out portions of the date. %A is the full name of the day of the week, %B is the full name of the month, etc.
You need 3 classes to set the date by representation:
NSCalendar* cal = [NSCalendar currentCalendar]; // 1.
NSDateComponents *comps = [[NSDateComponents alloc] init]; // 2.
[comps setYear:2012];
[comps setMonth:4];
[comps setDay:8];
NSDate* date = [cal dateFromComponents:comps]; // 3.
[comps release];