ios/xcode/objective-c: Display future dates in friendly format - ios

I have found some great solutions for displaying past dates in user friendly format such as just now, a few hours ago, yesterday, last week etc.
However, I've been unable to find a similar friendly format for future events/appointments.
I'm looking for something like, Today at 2PM. Tomorrow, Wednesday at 3:45PM. next Tuesday, September, 12th at 2PM. or for further away dates Friday, November 12th, 2015 at 2PM.
Can anyone recommend a category that does this, a tutorial or provide guidance in the form of a method to tackle this?
Thanks in advance for any suggestions.

Best user friendly date :
The solution is the same. You can build your solution on the link you mentioned.
[[NSDate date] timeIntervalSinceDate:date]; is a simple subtraction between two date who return positive or negative double if date is in the past or the futur.
After verifying if the date is in the past or the future some mathematics will give you the good user friendly string. For example, you can change the format depending on the parameters.
Simple user friendly :
If what you want is always string like "Wednesday, November 15th at 02:00PM", you can use NSDateFormater.
For your case :
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE, MMMM dd 'at' HH:mma"];
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:162000];
NSString *formattedDateString = [dateFormatter stringFromDate:date];
With this method date string will always take the same format.
Hope that's will help.

Related

iOS NSDateFormatter needs NSLocale even it's UTC

I have a doubt that I cannot understand why is the way it is and I appeal to the Gods of this site :)
I have a date coming like this:
"1982-01-01T00:00:00Z"
As I'm displaying whatever the server sends (I know, customer requirement, not good practice...), I'm forcing the device to have that TimeZone with the following method, simplified without error checking, not optimized, and all that kind of things:
+ (NSString *) yearStringFromDate: (NSDate *) date
{
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"YYYY"];
[formatter setTimeZone:[self timezoneForSIHF]];
return [formatter stringFromDate:date];
}
This should be UTC, BUT if I don't set the locale I'm getting, and JUST sometimes the incorrect year. So by adding this I get the year correct for all cases:
[formatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
For further info, I'm testing in a real device and simulator with different languages (en, de, es).
Why is this?
Why does the locale affect the date even though the timeZone is correct?
Why sometimes is working with some dates and sometimes it's not?
For example, 1982 is returning without setting the locale, 1981 and if I set it 1982. This doesn't happen with 1980, returning in both cases 1980 (or 1987, or ...)
Thanks in advance for all your replies :D
Cheers!
When converting ISO 8601/RFC 3339 date string to NSDate object, one uses the en_US_POSIX locale in case the user is not using a Gregorian calendar. See Technical Q&A 1480.
In your case, though, you are trying to get year string representation from date object. In that case you might not need en_US_POSIX. That's only necessary if you need to use Gregorian calendar regardless of what sort of calendar the device might currently be using.
As noted by others, though, you should be using yyyy and not YYYY. The former returns the calendar year. The latter returns the year, in "Week of Year" based calendars, which may not always be the same value as calendar year.
See the date formatting patterns for a discussion contrasting y and Y.
By the way, if you really need the year component of the date, you can also use the NSDateComponents related methods of NSCalendar.
Use yyyy instead of YYYY.
Reference.

Date conversion from string to NSDate in ios

I have searched over internet for a long time to get this but I can't find the solution. I have received a date string from web services as "22 May 2014", I have to convert into NSDate format for check it with current date. And I have to find out the date from web service is in future or in past time.
The actual problem is that when I convert this using
NSDate *date;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd MMMM YYYY"];
date = [dateFormatter dateFromString:dateString];
But I get an entirely Different Date, Sample Input dateString:22 June 2014 and Output I get is 2013-12-21 18:30:00+0000
Please suggest any solutions.
Thanks in advance. :)
You're using YYYY, which doesn't mean what you think it means. From the TR35-31 documentation, Y is the symbol for "year in week-of-year calendars".
You want dd MMMM yyyy instead as your format string. Mixing week-of-year-based fields and regular day/month/year fields is a recipe for odd problems.
Additionally, you may well want to set the time zone in your formatter - if you're just parsing a date, then you should consider using UTC, and make sure that all your calculations and formatting/parsing use UTC.
(I suspect the issue here is that week-of-year hasn't been set, so is assumed to be 1... and the week-year 2014 started on December 30th. Then the day-of-month is set to 22 by the dd part, and then your time zone offset of UTC+05:30 is taken into account.)

NSDate and NSDateformatter wrong output

So, i'm trying to create a NSDate object for sunrise and sunset. I get the date based on NSDatePicker, i get coordinates from a Map, and i get the timezone from the GPS from the map.
I use this code to get the NSDate object: https://github.com/MosheBerman/KosherCocoa-legacy
This one to get the coordinates: https://github.com/digdog/MapKitDragAndDrop
And this one to get the the timezone based on coordinates: https://github.com/Alterplay/APTimeZones.
Right now my physical location is in Los Angeles, and the sunrise and sunset i'm using to testing is back home in Denmark.
-(NSString *)sunriseDate{
//Create the GeoLocation based on 'latitude' and 'longitude' (getting the from MapKitDragAndDrop) and 'location.timeZone' (getting that from APTimeZones).
GeoLocation *position = [[GeoLocation alloc] initWithName:#"position" andLatitude:latitude andLongitude:longitude andTimeZone:location.timeZone];
AstronomicalCalendar *astronomicalCalender = [[AstronomicalCalendar alloc] initWithLocation:position];
//daysBetween is the value from NSDatePicker
astronomicalCalender.workingDate = [NSDate dateWithTimeIntervalSinceNow:kSecondsInADay*[self daysBetween]];
NSDate *sunriseDate = [astronomicalCalender sunrise];
NSLog(#"Sunrise time: %#", sunriseDate);
//This spits out: Sunrise time: 2014-03-05 06:09:53 AM +0000 which is the right time.
NSDateFormatter *sunriseTime = [[NSDateFormatter alloc] init];
[sunriseTime setDateFormat:#"HH:mm:ss"];
NSString *sunriseString = [sunriseTime stringFromDate:sunriseDate];
NSLog(#"Sunrisestring: %#", sunriseString);
//This spits out: 10:09:53 PM.
return sunriseString;
}
Why does this happen and can anyone maybe give me a solution to this?
To anyone who might stumble into the same thing.
I found a library on github https://github.com/Alterplay/APTimeZones that helped me determine the timezone based on the coordinates.
Then i used
[sunriseTime setTimeZone:location.timeZone];
This put out the right time for the timezone.
Hope this helps anyone!
You need to match the input format correctly.
You may only be interested in the time but the NSDateFormatter doesn't care. NSDate is never JUST a time. It is a point in time and so includes the date too. It doesn't work without the date and time sections.
Also, this is probably one of THE MOST ASKED questions on Stack Overflow. Any other NSDate to NSString (or vice versa) question will answer this.
Your date format should be...
#"YYYY-MM-dd hh:mm:ss a EEEE"
I believe. Something like that anyway.
This spits out: 10:09:53 PM. This is correct local time for your time zone, which differs by 8 hours from Greenwich time Sunrise time: 2014-03-05 06:09:53 AM +0000. That's all. You have evening when a german man wakes up.
As Fogmeister said, you should include the timezone when creating a NSDateFormatter. Take a loot at Apple's Docs, Data Formatting Guide:
Fixed Formats
To specify a custom fixed format for a date formatter, you use setDateFormat:. The format string uses the format patterns from the Unicode Technical Standard #35.
The Unicode official site:
http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns
You may try using this: [sunriseTime setDateFormat:#"yyyy-MM-dd hh:mm:ss a EEEE"];
instead of [sunriseTime setDateFormat:#"HH:mm:ss"];

NSDateFormatter: stringFromDate and dateFromString not reversible?

I'm having problems using a custom date formatter with NSDateFormatter to convert a string into a date. Here's a short example that creates a string from today's date but fails to convert this back to an NSDate:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"Mdyyyy"];
NSString *example = [dateFormatter stringFromDate:now]; // e.g., 10292013
NSDate *reverse = [dateFormatter dateFromString:example]; // nil?
So basically it seems that NSDateFormatter is creating a date string that it itself can't turn back into a NSDate using the same format that created the string.
Using MMddyyyy as the date string works, although I can't see from the documentation (which conveniently only goes up to iOS 6.0) why it would matter:
month M 1..2 09 Month - Use one or two for the numerical month, ....
...
day d 1..2 1 Date - Day of the month
The reason why I'm trying to use Mdyyyy instead of MMddyyyy is because it's closer to what NSDateFormatterShortStyle returns for my current NSLocale (M/d/yy).
Perhaps someone might have some insight here as two what I'm doing wrong, or if I'm wrong in my understanding of how this should work. (I know there are a lot of questions here regarding NSDateFormatter, but I didn't find one that fits my problem.)
Mdyyyy is ambiguous as a string ->date mapping. One cannot tell if "1112013" is Jan 11 or November 1. Hence NSDateFormatter will not allow it for string ->date.

How to get get a month and date in Objective C?

I am a new to objective C, I am developing a app to determine the date of birth when user gives the year and the number of days. For example if user give 1985 as his/her year of birth and the number of days as 311. his/here date of birth is 1985 November 6. So how to get the November 6 from 311 in 1985 ? Please help
You should never have to calculate whether the current year is a leap year or not. Never ever ever. Let the frameworks do that for you. People much more intelligent than you or I have done this for us already, so why on earth would we go about re-inventing this wheel with sub-optimal algorithms that would never account for all of the intricate calendar variations?
It's stupid to do this yourself. So don't:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *startComponents = [[NSDateComponents alloc] init];
[startComponents setYear:1985];
[startComponents setDay:311];
NSDate *date = [gregorian dateFromComponents:startComponents];
NSLog(#"endDate: %#", date);
This logs:
endDate: 1985-11-07 08:00:00 +0000
Something like this (not tested):
NSDateFormatter *df = [[NSDateFormatter alloc] init] autorelease];
[df setDateFormat:#"yyyy"];
NSDate *date1 = [df dateWithString:#"1985"];
NSDate *date2 = [df dateByAddingTimeInterval:60*60*24*311]; //
First off, why are you getting the number of days from someone instead of getting the month and day. Users will not know what day of the year they are born and will be frustrated to try and figure it out.
To answer your question, you could have an array that stores the number of days at the end of each month {31, 28, 31, 30, ...} and use that as a reference (subtracting the total in a loop). You'll also have to check if the year was a leap year and subtract one from the total if its over 59.
You don't need anything specific from Objective-C... first you need to know if the year is a leap year. Then you need to count the days from the months until you end with your target day.

Resources