Algorithm: Resolution Time - ios

I have an enquiry that needs to be resolved in fixed hour (Critical in 4hr, Important in 10hr and Normal in 24 hr). The enquiry res hours can be increased if there's a non working hour in between or a holiday. Non working can be full day or some hour in a specific day.
For eg: A critical enquiry raised at 08:02am on Monday should get resolved by 01:00pm
//Working hours of week
Mon 09:00am - 01:00pm
Tue Holiday
Wed 09:00am - 05:00pm(non working between 01:00pm - 02:00pm)
Thu 11:00am - 03:00pm(non working between 01:00pm - 02:00pm)
Fri 09:00am - 05:00pm(non working between 01:00pm - 02:00pm)
The inputs are enquiry type and enquiry log time. Output required is the resolution time.
My Approach:
Add all res hours to an enquiry as if all hrs are working. So, if log time is 08:02am for a critical enq add 4hrs i.e. 12:02pm as res time.
Enter while(true) loop where I check if next hr is a work time. If yes skip that hr else add that to res time and continue.
But this approach does not give me correct results when log time is non working.
NSDate *enqExpiration = nil;
int hoursNeededToCoverEnq = 0;
switch (enqType) {
case normalPriority:
hoursNeededToCoverEnq = lowResHours;
enqExpiration = [NSDate dateWithTimeInterval:lowResHours*hour sinceDate:capturedTime];
break;
case importantPriority:
hoursNeededToCoverEnq = mediumResHours;
enqExpiration = [NSDate dateWithTimeInterval:mediumResHours*hour sinceDate:capturedTime];
break;
case criticalPriority:
hoursNeededToCoverEnq = highResHours;
enqExpiration = [NSDate dateWithTimeInterval:highResHours*hour sinceDate:capturedTime];
break;
}
int aggregatedHrs = 0;
while(true){
capturedTime = [NSDate dateWithTimeInterval:1*hour sinceDate:capturedTime];
NSDateFormatter *dayFormat = [[NSDateFormatter alloc] init];
[dayFormat setTimeZone: [NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
[dayFormat setDateFormat:#"EEEE"];
NSString* capturedDay = [dayFormat stringFromDate:capturedTime];
[dayFormat setDateFormat:#"dd/MM/yyyy"];
NSString* todayDate = [dayFormat stringFromDate:capturedTime];
if([weekends containsObject:capturedDay]){
enqExpiration = [NSDate dateWithTimeInterval:1*hour sinceDate:enqExpiration];
continue;
}else if([holidays containsObject:todayDate]){
enqExpiration = [NSDate dateWithTimeInterval:1*hour sinceDate:enqExpiration];
continue;
}else{
NSString *openTime, *closeTime;
for(int i=0; i<weekdaysTime.count; i++){
if([[((NSMutableDictionary*)[weekdaysTime objectAtIndex:i]) valueForKey:#"workingDay"] isEqualToString:capturedDay]){
openTime = [((NSMutableDictionary*)[weekdaysTime objectAtIndex:i]) valueForKey:#"openingTime"];
closeTime = [((NSMutableDictionary*)[weekdaysTime objectAtIndex:i]) valueForKey:#"closingTime"];
break;
}
}
NSDate *openTimeToday = nil, *closeTimeToday = nil;
[dayFormat setDateFormat:#"dd/MM/yyyy hh:mmaa"];
openTimeToday = [dayFormat dateFromString:[[todayDate stringByAppendingString:#" "] stringByAppendingString:openTime]];
closeTimeToday = [dayFormat dateFromString:[[todayDate stringByAppendingString:#" "] stringByAppendingString:closeTime]];
if([capturedTime compare:openTimeToday]==NSOrderedAscending || [capturedTime compare:closeTimeToday]==NSOrderedDescending ){
enqExpiration = [NSDate dateWithTimeInterval:1*hour sinceDate:enqExpiration];
continue;
}
}
aggregatedHrs ++;
if( aggregatedHrs == hoursNeededToCoverEnq )
break;
}
return enqExpiration;

Related

how to identify the current subscription plan in in app purchase [auto renewal]

I have three subscription plans in in-app-purchase 1 month,6 months,1 year so i want to check the users current subscription plan and date of expire so what i am doing right now is from receipt getting latest_receipt_info in that I am using the last object.
from the last object, I am taking product_id and using it as a current subscription plan and expires_date used to check active or not.
Below is the block of code I am using.
So is this the correct approach?
if([dict[#"status"] integerValue] == 0) {
if([dict.allKeys containsObject:#"latest_receipt_info"]) {
NSArray *iapReceipts = dict[#"latest_receipt_info"];
if(iapReceipts) {
if(iapReceipts.count > 0) {
NSDictionary *latestReceipt = [iapReceipts lastObject];
if(latestReceipt) {
_currentIAPID = latestReceipt[#"product_id"];
NSDate *expireDate = latestReceipt[#"expires_date"];
if(expireDate) {
NSInteger days = DaysBetween(NSDate.date, expireDate);
if(days >= 0) {
NSLog(#"days %ld",(long)days);
status = SubscriptionStatusActive;
} else {
NSLog(#"Subs :NEGATIVE DAYS");
status = SubscriptionStatusExpired;
}
}
}
}
}
}
}
Any suggestions would be more helpful.
No, it's not a correct approach. You shouldn't get last object because that array is not sorted. It contains all your transactions including all renewals. This example code doesn't take into account cancellation_date:
- (void)parseResponse:(NSDictionary*)dict{
if ([dict[#"status"] integerValue] != 0) {return;}
NSArray *iapReceipts = dict[#"latest_receipt_info"];
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = #"yyyy-MM-dd HH:mm:ss VV";
for (NSDictionary *iapReceipt in iapReceipts){
NSString *productID = iapReceipt[#"product_id"];
NSDate *date = [formatter dateFromString:iapReceipt[#"expires_date"]?:#""];
if (date && [date timeIntervalSinceDate:[NSDate date]] > 0){
[[NSUserDefaults standardUserDefaults] setObject:date forKey:productID];
}
}
}
- (BOOL)isSubscriptionActive:(NSString*)productID {
NSDate *date = [[NSUserDefaults standardUserDefaults] objectForKey:productID];
if (date && [date timeIntervalSinceDate:[NSDate date]] > 0){
return YES;
} else {
return NO;
}
}

Handle Foursquare hours API to find out if the venue is opened or closed

I have a foursquare hours array (Foursquare API) that stores segments of hours when a specific venue is open. It looks something like this:
[{
"days":[1,2,3,4,7],
"includesToday":true,
"open":[
{"end":"+0200","start":"1000"}],
"segments":[]},
{
"days":[5,6]
,"open":[
{"end":"+0300","start":"1000"}],
"segments":[]}
]
How do I find out if the venue is opened or closed at current time?
I handle it like this: 4sq hours API gist
-(NSDictionary*)isVenueOpenDictionaryForHours:(NSArray*)hours{
// defaults and inits
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDictionary *lastSegmentYesterday = [[NSDictionary alloc] init];
NSDate *dateNow = [NSDate date];
NSString *venueOpenText = [[NSString alloc] init];
NSString *venueOpen = #"no";
// get components for today
NSDateComponents *compsNow = [gregorian components:NSWeekdayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:dateNow];
// get weekday for today and yesterday so we can lookup 4sq API
NSInteger weekday = [compsNow weekday];
NSInteger weekdayYesterday = (weekday>1)?weekday-1:7;
// look for todays' segment
NSMutableArray *venueOpenSegments = [[NSMutableArray alloc] init]; // stores all the segments when the venue is open
for (NSDictionary *segment in hours){
// get today's segment (if it exists)
if ([segment[#"days"] containsObject:[NSNumber numberWithInteger:weekday]]){
for (NSDictionary *dictOpen in segment[#"open"])
[venueOpenSegments insertObject:#{#"end": [dictOpen[#"end"] mutableCopy], #"start":[dictOpen[#"start"] mutableCopy]}.mutableCopy atIndex:venueOpenSegments.count];
}
// check the day before if the venue is open past midnight
if (([segment[#"days"] containsObject:[NSNumber numberWithInteger:weekdayYesterday]] && [segment[#"open"] count])){
// get the last segment (that should be the one passing midnight)
NSDictionary *tempSegment = [segment[#"open"] lastObject];
// if it has more than 4 characters it's after midnight ("+02:00"), also, ignore if it closes at midnight
if ([tempSegment[#"end"] length] > 4 && ![tempSegment[#"end"]isEqualToString:#"+0000"]){
// create a new segment that starts at midnight and lasts till the time it closes (early AMs usually)
lastSegmentYesterday = #{#"start":#"0000", #"end":[tempSegment[#"end"] substringFromIndex:1]};
}
}
}
// add last night segment that passes midnight as the first segment of today
if (lastSegmentYesterday.count){
[venueOpenSegments insertObject:lastSegmentYesterday atIndex:0];
}
// go through all the segments and find out if the venue is closed or open
if (venueOpenSegments.count){
NSDateComponents *comps = [[NSDateComponents alloc] init];
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc]init];
timeFormatter.dateFormat = #"HH:mm"; // set time output format
int segmentNumber = 0;
for (NSMutableDictionary *segment in venueOpenSegments){
segmentNumber++;
// confing start date
[comps setDay:compsNow.day];
[comps setMonth:compsNow.month];
[comps setYear:compsNow.year];
[comps setHour:[[segment[#"start"] substringToIndex:2] intValue]];
[comps setMinute:[[segment[#"start"] substringFromIndex:2] intValue]];
NSDate *dateStart = [[[NSCalendar currentCalendar] dateFromComponents:comps] copy];
// config end date
// check if the segment goes to next day
BOOL closesTomorrow = NO;
if ( [segment[#"end"] length]==5 ){
segment[#"end"] = [segment[#"end"] substringFromIndex:1];
closesTomorrow = YES;
}
[comps setHour:[[segment[#"end"] substringToIndex:2] intValue]];
[comps setMinute:[[segment[#"end"] substringFromIndex:2] intValue]];
NSDate *dateEnd = [[[NSCalendar currentCalendar] dateFromComponents:comps] copy];
// add a day if it closes tomorrow
if (closesTomorrow){
NSDateComponents *nextDayComponent = [[NSDateComponents alloc] init];
nextDayComponent.day = 1;
dateEnd = [gregorian dateByAddingComponents:nextDayComponent toDate:dateEnd options:0];
}
// start checking if it's open or closed
// now < segment start
if ([dateNow compare:dateStart] == NSOrderedAscending){
venueOpenText = [NSString stringWithFormat:#"opens at %#",[timeFormatter stringFromDate: dateStart]];
venueOpen = #"later";
break;
}
// segment end < now
else if ([dateEnd compare:dateNow] == NSOrderedAscending){
if (segmentNumber == venueOpenSegments.count){
venueOpenText = [NSString stringWithFormat:#"closed since %#",[timeFormatter stringFromDate: dateEnd]];
break;
}
continue;
}
// segment start < now < segment end
else if ([dateStart compare:dateNow] == NSOrderedAscending && [dateNow compare:dateEnd] == NSOrderedAscending){
venueOpenText = [NSString stringWithFormat:#"open till %#",[timeFormatter stringFromDate: dateEnd]];
venueOpen = #"yes";
break;
}
// rare but possible... last minute of the venue being open (I treat it as closed)
else {
venueOpenText = #"closing right now";
}
}
}
else venueOpen = #"closed today"; // no segments for today, so it's closed for the dayæ
// return results
return #{#"open":venueOpen, #"string":venueOpenText};
}
and I update my UILabel like this:
NSDictionary *venueOpen = [self isVenueOpenDictionaryForHours:_arrayVenues[indexPath.row][#"hours"]];
label.text = venueOpen[#"string"];
if ([venueOpen[#"open"] isEqualToString:#"no"]){
label.textColor = [UIColor colorWithHexString:#"b91d47" alpha:1]; // red
} else if ([venueOpen[#"open"] isEqualToString:#"yes"]) {
label.textColor = [UIColor colorWithHexString:#"1e7145" alpha:1]; // green
} else if ([venueOpen[#"open"] isEqualToString:#"later"]) {
label.textColor = [UIColor colorWithHexString:#"e3a21a" alpha:1]; // yellow
}
BTW, I use pod 'HexColors' for colorWithHexString methods

Setting Reminder with a dueDate with Recurrence Rule iOS

Question: How do I properly set my reminder due date since I have a recurrence rule?
Here is what the reminder object looks like:
EKReminder <0x1700cf490> {title = Dickens's CANINE GOLD WELLNESS doses[1.00]; **dueDate = (null)**; **completionDate = (null)**; priority = 0; calendarItemIdentifier = D1D99FEA-2BFA-4DB1-9D86-7FB26246B50A; alarms = (
"EKAlarm <0x1780a9420> {triggerInterval = -79200.000000}"
)}
The error I am getting is:
Reminder Error=[A repeating reminder must have a due date.]
You can see in the code that I am fooling around with NSDateComponents as a solution since startDateComponents which I just set the month/day/year and local timezone of the reminder which will produce an all day reminder, which in this case is fine. I will probably move the date components and setting of the due date inside the recurrence section when it is done.
Here is my code:
-(void)setReminders:(NSString *)reminderText
andDate:(NSString *)reminderdate
andPetName:(NSString*)petName
andDose:(NSNumber *)dose {
EKEventStore *store = [[EKEventStore alloc] init];
NSDate * reminderNewDate = [self getDateFromString:reminderdate];
petName = [ConfigOps readProperty:kConfigOpsPetKey];
NSString *reminderTitle = [NSString stringWithFormat:#"%#'s %#", petName, reminderText];
NSUInteger doseCount = 0;
if ([dose integerValue] != 0 || dose != nil) {
doseCount = [dose integerValue];
}
else{
doseCount = 0;//NOTE: looks like purchases will have doses not reminders so set to 0 for now.
}
[store requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
// access code here
EKReminder *new_reminder = [EKReminder reminderWithEventStore:store];
new_reminder.title = reminderTitle;
new_reminder.calendar = store.defaultCalendarForNewEvents;
//get the date components
NSDateComponents *comp = [[NSDateComponents alloc]init];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =
[gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit |
NSWeekdayCalendarUnit) fromDate:reminderNewDate];
NSInteger day = [weekdayComponents day];
NSInteger month = [weekdayComponents month];
//NSInteger weekday = [weekdayComponents weekday];//future reference
NSInteger year = [weekdayComponents yearForWeekOfYear];
//Month is dose+month = end of reccurence
month = month + doseCount;
[comp setYear:year];
[comp setMonth:month];
[comp setDay:day];
NSDate *date = [gregorian dateFromComponents:comp];
NSTimeZone *myNSTimeZone = gregorian.timeZone;
NSDateComponents *start = new_reminder.startDateComponents;
start.timeZone = myNSTimeZone;
start.month = [weekdayComponents month];
start.day = [weekdayComponents day];
start.year = [weekdayComponents yearForWeekOfYear];
new_reminder.startDateComponents = start;
new_reminder.dueDateComponents = start;
new_reminder.completed = NO;
//Create alarm 22 hours before
double alarmAmountInSeconds = 60.0*60.0*22.0;
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:(-1.0*alarmAmountInSeconds)];
[new_reminder addAlarm:alarm];
//new_reminder.alarms = [NSArray arrayWithObject:alarm];
//create nice text for note.
//Hey there! petName needs remindertext from your friendly clinic, clinicName!
new_reminder.notes = reminderText;
if (doseCount != 0) {
EKRecurrenceRule *recurranceRule = [[EKRecurrenceRule alloc] initRecurrenceWithFrequency:EKRecurrenceFrequencyMonthly
interval:1
end:[EKRecurrenceEnd recurrenceEndWithOccurrenceCount:doseCount]
];
new_reminder.calendar = [store defaultCalendarForNewReminders];
[new_reminder addRecurrenceRule:recurranceRule];
}
NSError *er;
//EKEventEditViewController
BOOL success = [store saveReminder:new_reminder commit:YES error:&er];
if (success) {
// Handle here
NSString *alertMessage = [NSString stringWithFormat:#"Reminder Created for\n%#", reminderTitle];
NSString *alertTitle = #"Please check your Reminders";
UIAlertView *alertR = [[UIAlertView alloc]initWithTitle: alertTitle
message: alertMessage
delegate: self
cancelButtonTitle:nil
otherButtonTitles:#"OK",nil];
[alertR show];
}
else{
//log error
NSLog(#" Reminder Error=[%#]", [er localizedDescription]);
//log to error table in database &inform Flurry?
}
}];
}
The method works if there is no recurrence set since it doesn't require a start date/due date.
After some fixing of the date (I found was returning nil), I found that I have to set and end recurrence rule when adding a dose amount.
Here is the code which gets rid of the error (which is pretty funny of Apple to have - kudos Apple!).
if (doseCount != 0) {
EKRecurrenceRule *recurranceRule = [[EKRecurrenceRule alloc] initRecurrenceWithFrequency:EKRecurrenceFrequencyMonthly
interval:1
end:[EKRecurrenceEnd recurrenceEndWithOccurrenceCount:doseCount]
];
new_reminder.calendar = [store defaultCalendarForNewReminders];
//FIX for : recuurence end - Reminder Error = [A repeating reminder must have a due date.]
EKRecurrenceEnd *endRec = [EKRecurrenceEnd recurrenceEndWithEndDate:date];
EKRecurrenceRule *recur = [[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyDaily interval: 1 end:endRec];
unsigned unitFlags= NSYearCalendarUnit|NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |NSMinuteCalendarUnit|NSSecondCalendarUnit|NSTimeZoneCalendarUnit;
NSDateComponents *dailyComponents=[gregorian components:unitFlags fromDate:date];
[new_reminder setDueDateComponents:dailyComponents];
[new_reminder addRecurrenceRule:recur];
//add it.
[new_reminder addRecurrenceRule:recurranceRule];
}
Hope this helps someone get through this.
For those looking for Swift version:
func editReminder(r: EKReminder) -> Bool {
if(r.recurrenceRules.count > 0 && r.dueDateComponents == nil) {
let startDate = NSDate()
let dueDate: NSDate = NSDate(timeIntervalSinceNow: 31536000) // 1 year from now
let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
let unitFlags = NSCalendarUnit(UInt.max)
r.dueDateComponents = gregorian?.components(unitFlags, fromDate: dueDate)
}
var error: NSError?
return eventStore.saveReminder(r, commit: true, error: &error)
}

EKEvent is not added according to given EKRecurrenceRule

I'm trying to add an event into calendar with recurrence rule RRULE:FREQ=YEARLY;BYMONTH=6,7;BYDAY=1TH
So according to this rule the event should be added yearly, each 1st thursday of june and july until expire date, which I've set in my project.
In my project, events are created but not according to the recurrence rule. With the following code the events added only on each 1st thursday of june. Why the events are not added on 1st thursday of each july also?
Here is .m file code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self createEvent];
}
- (void)createEvent
{
EKEventStore *eventStore = [[EKEventStore alloc] init];
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.title = #"testRecurrenceRule";
event.location = #"Dhaka";
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
event.startDate = [self dateFromString:#"2013-06-18T21:00:00+06:00"];
event.endDate = [self dateFromString:#"2013-06-18T22:00:00+06:00"];
id recurrenceRule = [self recurrenceRuleForEvent];
if(recurrenceRule != nil)
[event addRecurrenceRule:recurrenceRule];
if ([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
// iOS 6 and later
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self saveTheEvent:event eventStore:eventStore];
//[eventStore saveEvent:event span:EKSpanThisEvent error:error];
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
//do nothing
});
}
}];
}
else
{
[self saveTheEvent:event eventStore:eventStore];
}
textView.text = [NSString stringWithFormat:#"Event has been added with recurrence rule %#",recurrenceRule];
}
- (void)saveTheEvent:(EKEvent *)aEvent eventStore:(EKEventStore *)aStore
{
[aStore saveEvent:aEvent span:EKSpanThisEvent error:NULL];
}
- (EKRecurrenceRule *)recurrenceRuleForEvent
{
//just creating a recurrence rule for RRULE:FREQ=YEARLY;BYMONTH=6,7;BYDAY=1TH
// setting the values directly for testing purpose.
//FREQ=YEARLY
EKRecurrenceFrequency recurrenceFrequency = EKRecurrenceFrequencyYearly;
NSInteger recurrenceInterval = 1;
EKRecurrenceEnd *endRecurrence = nil;
NSMutableArray *monthsOfTheYearArray = [NSMutableArray array];
NSMutableArray *daysOfTheWeekArray = [NSMutableArray array];
NSMutableArray *daysOfTheMonthArray = [NSMutableArray array];
NSMutableArray *weeksOfTheYearArray = [NSMutableArray array];
NSMutableArray *daysOfTheYearArray = [NSMutableArray array];
NSMutableArray *setPositionsArray = [NSMutableArray array];
//BYMONTH=6,7
[monthsOfTheYearArray addObject:[NSNumber numberWithInt:6]];
[monthsOfTheYearArray addObject:[NSNumber numberWithInt:7]];
//BYDAY=1TH
[daysOfTheWeekArray addObject:[EKRecurrenceDayOfWeek dayOfWeek:5 weekNumber:1]];
endRecurrence = [EKRecurrenceEnd recurrenceEndWithEndDate:[self dateFromString:#"2018-12-15T22:30+06:00"]];
EKRecurrenceRule *recurrence = [[EKRecurrenceRule alloc] initRecurrenceWithFrequency:recurrenceFrequency
interval:recurrenceInterval
daysOfTheWeek:daysOfTheWeekArray
daysOfTheMonth:daysOfTheMonthArray
monthsOfTheYear:monthsOfTheYearArray
weeksOfTheYear:weeksOfTheYearArray
daysOfTheYear:daysOfTheYearArray
setPositions:setPositionsArray
end:endRecurrence];
return recurrence;
}
- (NSDate *)dateFromString:(NSString *)string
{
//check if the date string in null
if ([string length] == 0)
return nil;
NSString *dateString = nil;
NSString *modifiedString = nil;
BOOL secSpotMissing = false;
NSRange range = [string rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:#"T"]];
if (range.location != NSNotFound)
{
dateString = [string substringFromIndex:range.location];
range = [dateString rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:#"+-Z"]];
if (range.location != NSNotFound)
{
//seperate the time portion of date string and checking second field is missing or not. like is it HH:mm or HH:mm:ss?
if ([[[dateString substringToIndex:range.location] componentsSeparatedByString:#":"] count] < 3)
secSpotMissing = true;
//seperate the time zone portion and checking is there any extra ':' on it. It should like -0600 not -06:00. If it has that extra ':', just replacing it here.
dateString = [dateString substringFromIndex:range.location];
if([dateString hasSuffix:#"Z"])
modifiedString = [dateString stringByReplacingOccurrencesOfString:#"Z" withString:#"+0000"];
else
modifiedString = [dateString stringByReplacingOccurrencesOfString:#":" withString:#""];
string = [string stringByReplacingOccurrencesOfString:dateString withString:modifiedString];
}
}
else
return nil;
// converting the date string according to it's format.
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
if (secSpotMissing)
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mmZZZ"];
else
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZ"];
return [dateFormatter dateFromString:string];
}
Can somebody please help me regarding this?
This seems a repeat of another question. Basically, according to "BYDAY" rule, the 1st for YEARLY frequency means the first week in the year - instead of 1st week each month.
#Shuvo, I did not read rfc. But here is Apple document EKRecurrenceDayOfWeek.
The EKRecurrenceDayOfWeek class represents a day of the week for use with an EKRecurrenceRule object. A day of the week can optionally have a week number, indicating a specific day in the recurrence rule’s frequency. For example, a day of the week with a day value of Tuesday and a week number of 2 would represent the second Tuesday of every month in a monthly recurrence rule, and the second Tuesday of every year in a yearly recurrence rule.
When you say "1st Thursday", that is correct - except in the context of yearly, it is 1st thursday of the year.
The bug was confirmed by Apple, at least until iOS 7.1.3 (which is the latest available version at this moment).

iOS - Friendly NSDate format

I need to display the date of posts in my app to the user, right now I do it in this format: "Fri, 25 May". How would I format an NSDate to read something like "2 hours ago"? To make it more user friendly.
Take a look at FormaterKit https://github.com/mattt/FormatterKit
Created by mattt who also created AFNetworking.
NSDateFormatter can't do things like that; you're going to need to establish your own rules. I guess something like:
- (NSString *)formattedDate:(NSDate *)date
{
NSTimeInterval timeSinceDate = [[NSDate date] timeIntervalSinceDate:date];
// print up to 24 hours as a relative offset
if(timeSinceDate < 24.0 * 60.0 * 60.0)
{
NSUInteger hoursSinceDate = (NSUInteger)(timeSinceDate / (60.0 * 60.0));
switch(hoursSinceDate)
{
default: return [NSString stringWithFormat:#"%d hours ago", hoursSinceDate];
case 1: return #"1 hour ago";
case 0:
NSUInteger minutesSinceDate = (NSUInteger)(timeSinceDate / 60.0);
/* etc, etc */
break;
}
}
else
{
/* normal NSDateFormatter stuff here */
}
}
So that's to print 'x minutes ago' or 'x hours ago' up to 24 hours from the date, which will usually be one day.
I wanted a date format like Facebook does for their mobile apps so I whipped up this NSDate category - hope it is useful for someone (this kind of stuff should really be in a standard library!) :)
https://github.com/nikilster/NSDate-Time-Ago
There's also SEHumanizedTimeDiff which does/is about to support multiple languages if that's an issue for you:
https://github.com/sarperdag/SEHumanizedTimeDiff
There are about a million ways you could do this, but here's a quick one:
NSString* hoursAgo = [NSString stringWithFormat:#"%.0lf hours ago", fabs([date timeIntervalSinceNow] / 3600.0)]
Of course, this doesn't check that date is actually from the past, doesn't do anything but hours, etc. But, you probably get the idea.
timeIntervalSinceNow returns how many seconds have passed since a given date, with positive numbers being a date in the future and negative numbers being a date in the past. So, we get how many seconds have passed, divide it by 3600 seconds in an hour to compute the hours that have passed, and then put its absolute value into the string "n hours ago".
Here is a pretty good answer this will take in seconds since the epoch(Jan 1, 1970) and return you a nice formatted string like '3 minutes ago'. Simply call it with your date object like so:
[timeAgoFromUnixTime:[myDateObject timeIntervalSince1970]];
+ (NSString *)timeAgoFromUnixTime:(double)seconds
{
double difference = [[NSDate date] timeIntervalSince1970] - seconds;
NSMutableArray *periods = [NSMutableArray arrayWithObjects:#"second", #"minute", #"hour", #"day", #"week", #"month", #"year", #"decade", nil];
NSArray *lengths = [NSArray arrayWithObjects:#60, #60, #24, #7, #4.35, #12, #10, nil];
int j = 0;
for(j=0; difference >= [[lengths objectAtIndex:j] doubleValue]; j++)
{
difference /= [[lengths objectAtIndex:j] doubleValue];
}
difference = roundl(difference);
if(difference != 1)
{
[periods insertObject:[[periods objectAtIndex:j] stringByAppendingString:#"s"] atIndex:j];
}
return [NSString stringWithFormat:#"%li %#%#", (long)difference, [periods objectAtIndex:j], #" ago"];
}
In newer versions of iOS since this question was asked, NSDateFormatter has had this ability added. It can now do it using the doesRelativeDateFormatting property.
+(NSString*)HourCalculation:(NSString*)PostDate
{
NSLog(#"postdate=%#",PostDate);
// PostDate=#"2014-04-02 01:31:04";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSTimeZone *gmt = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
[dateFormat setTimeZone:gmt];
NSDate *ExpDate = [dateFormat dateFromString:PostDate];
NSLog(#"expdate=%#",ExpDate);
NSLog(#"expdate=%#",[NSDate date ]);
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSDayCalendarUnit|NSWeekCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit|NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:ExpDate toDate:[NSDate date] options:0];
// NSLog(#"year=%d",components.year);
//
// NSLog(#"month=%d",components.month);
//
// NSLog(#"week=%d",components.week);
//
// NSLog(#"day=%d",components.day);
//
// NSLog(#"hour=%d",components.hour);
//
// NSLog(#"min=%d",components.minute);
//
// NSLog(#"sce=%d",components.second);
//
NSString *time;
if(components.year!=0)
{
if(components.year==1)
{
time=[NSString stringWithFormat:#"%ld year",(long)components.year];
}
else{
time=[NSString stringWithFormat:#"%ld years",(long)components.year];
}
}
else if(components.month!=0)
{
if(components.month==1)
{
time=[NSString stringWithFormat:#"%ld month",(long)components.month];
}
else{
time=[NSString stringWithFormat:#"%ld months",(long)components.month];
}
// NSLog(#"%#",time);
}
else if(components.week!=0)
{
if(components.week==1)
{
time=[NSString stringWithFormat:#"%ld week",(long)components.week];
}
else{
time=[NSString stringWithFormat:#"%ld weeks",(long)components.week];
}
// NSLog(#"%#",time);
}
else if(components.day!=0)
{
if(components.day==1)
{
time=[NSString stringWithFormat:#"%ld day",(long)components.day];
}
else{
time=[NSString stringWithFormat:#"%ld days",(long)components.day];
}
}
else if(components.hour!=0)
{
if(components.hour==1)
{
time=[NSString stringWithFormat:#"%ld hour",(long)components.hour];
}
else{
time=[NSString stringWithFormat:#"%ld hours",(long)components.hour];
}
}
else if(components.minute!=0)
{
if(components.minute==1)
{
time=[NSString stringWithFormat:#"%ld min",(long)components.minute];
}
else{
time=[NSString stringWithFormat:#"%ld mins",(long)components.minute];
}
// NSLog(#"time=%#",time);
}
else if(components.second>=0){
// NSLog(#"postdate=%#",PostDate);
// NSLog(#"expdate=%#",[NSDate date ]);
if(components.second==0)
{
time=[NSString stringWithFormat:#"1 sec"];
}
else{
time=[NSString stringWithFormat:#"%ld secs",(long)components.second];
}
}
return [NSString stringWithFormat:#"%# ago",time];
}
This code will show you time in
------------sec like 2 sec ago
------------min like 2 mins ago
------------hours like 2 hours ago
------------days like 2 days ago
------------week like 2 weeks ago
------------month like 2 months ago
Lastly....
years like 2 years ago
:) try this
Adding to the solution try this more simplified method
NSDateComponents *today = [[NSCalendar currentCalendar] components:NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond fromDate:passed toDate:[NSDate date] options:0];
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:date];
if (interval < 60) timestampString = [NSString stringWithFormat:#"%d seconds ago" ,today.second];
else if (interval < 60 * 60) timestampString = [NSString stringWithFormat:#"%d minutes ago" ,today.minute];
else if (interval < 60 * 60 * 24) timestampString = [NSString stringWithFormat:#"%d hours ago" ,today.hour];
else timestampString = [NSString stringWithFormat:#"%d days ago" ,today.day];

Resources