How to judge whether selected date has exceeded the range in UIDatePicker? - ios

Now I have set the minimumDate and maximumDate of UIDatePicker like this
_timePicker.minimumDate = [[NSDate date] dateByAddingTimeInterval:60];
_timePicker.maximumDate = [[NSDate date] dateByAddingTimeInterval:86400*10];
and I have added a target
[_timePicker addTarget:self action:#selector(labelContentDidChange:) forControlEvents:UIControlEventValueChanged];
I want to show an alert when a user has selected date which is not in that range, but every time the labelContentDidChange is invoked, the date property has been changed automatically and I can't get what the user has selected before, for example, if I select time currently, the datePicker will scroll to time one minute later,and the date I get in labelContentDidChange is already one minute later.

Maybe compare date that user have picked to minimum and maximum dates?
// assume we have NSDate* pickedDate
NSDate *minimumDate = [[NSDate date] dateByAddingTimeInterval:60];
NSDate *maximumDate = [[NSDate date] dateByAddingTimeInterval:86400*10];
// if picked date is earlier than minimumDate, OR if it is later than maximumDate - show alert
if ([pickedDate compare:minimumDate] == NSOrderedAscending ||
[pickedDate compare:maximumDate] == NSOrderedDescending) {
// show your alert
} else {
// valid date was picked
}
Though if you set these minimum and maximum as properties to your datePicker user would not be able to choose invalid dates, it would only makes sense for some other custom periods of times...

Related

What is the proper way to convert date object with separate timezone into NSDate

My app ingests data from a web service (PHP) which provides dates in this format:
endDate = {
date = "2020-09-30 16:16:08.000000";
timezone = "-04:00";
"timezone_type" = 1;
};
This is the code I have been using to convert to NSDate, and it works as far as I can tell, in every test, but it fails on a few devices according to user reports and debug logs.
Note that the correct conversion of this date determines if content is unlocked in the app, so when it fails, customers contact us about it.
NSDictionary* dateDict = [responseDict objectForKey:#"endDate"];
NSString* strEndDate = [dateDict objectForKey:#"date"];
NSString* strOffset = [dateDict objectForKey:#"timezone"];
NSTimeInterval zoneSeconds = 0;
NSRange rng = [strOffset rangeOfString:#":"];
if (rng.location != NSNotFound && rng.location >= 1)
{
NSString* hoursOnly = [strOffset substringToIndex:rng.location];
NSInteger offsetValue = [hoursOnly integerValue];
zoneSeconds = (3600 * offsetValue);
}
NSDateFormatter* df = [[NSDateFormatter alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:zoneSeconds];
[df setTimeZone:timeZone];
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss.000000"];
NSDate* newEndDate = [df dateFromString:strEndDate];
However, debug logs from a few users show that the dateFromString call is failing and returning nil.
We have one user who has 2 iOS devices, and using the same account (same date) the app performs as expected on one of them, but fails on the other. Same Apple ID, both running iOS12. Debug logs show both devices received the same date from the server, yet one of them failed to convert the date from a string to NSDate.
My assumption so far is that there is some setting or configuration on the device(s) where this fails that is different. But I have fiddled with calendar and date settings all day, and cannot get this to fail. I know the user in question has both devices configured to the same time zone.
Is there a better, more correct way to do this date conversion which might be more robust?
When using an arbitrary date format it's highly recommended to set the locale of the date formatter to the fixed value en_US_POSIX.
Rather than calculating the seconds from GMT it might be more efficient to strip the milliseconds with regular expression, append the string time zone and use an appropriate date format.
This code uses more contemporary syntax to set date formatter properties with dot notation and dictionary literal key subscription
NSDictionary *dateDict = responseDict[#"endDate"];
NSString *strEndDate = dateDict[#"date"];
NSString *strTimeZone = dateDict[#"timezone"];
NSString *dateWithoutMilliseconds = [strEndDate stringByReplacingOccurrencesOfString:#"\\.\\d+" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, strEndDate.length)];
NSString *dateWithTimeZone = [NSString stringWithFormat:#"%#%#", dateWithoutMilliseconds, strTimeZone];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.locale = [NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"];
df.dateFormat = #"yyyy-MM-dd HH:mm:ssZZZZZ"];
NSDate *newEndDate = [df dateFromString:dateWithTimeZone];
The question was actually similar to (What is the best way to deal with the NSDateFormatter locale "feechur"?) as was suggested originally, but it was this other question (NSDateFormatter fails to return a datetime for UK region with 12 hour clock set) which really made it click for me - its the UK region with the 12hour clock which causes the code to fail, but the dateFormatter was easily fixed by simply setting the locale to "un_US_POSIX" as suggested in the answer to that question (it was also suggested below by vadian - I did not try his code however). Thank you to everyone who contributed hints and leads!

How to set the maximum date in MDDatePicker in objective c

I am Setting Maximum date but not able to disable Remaining date
Example like - Date of Birth Selection.
Any one has idea about that.
thanks in Advance.
-(void) dateTextField:(id)sender
{
UIDatePicker *picker = (UIDatePicker*) dateOfBirthField.inputView;
// [picker setMaximumDate:[NSDate date]];
[picker setMinimumDate:[NSDate date]];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
NSDate *eventDate = picker.date;
[dateFormat setDateFormat:#"yyyy/MM/dd"];
NSString *dateString = [dateFormat stringFromDate:eventDate];
dateOfBirthField.text = [NSString stringWithFormat:#"%#",dateString];
}
MDDatePickerDialog class uses MDCalendar to manage its minimum date. If you will look at the implementation of MDCalendar you will find following implementation in initialize method:
_maximumDate = [NSDateHelper mdDateWithYear:2037 month:12 day:31];
First try setting this date to a static value of your choice to see this is the required variable, then you can move this property declaration to header file of MDCalendar to make this maximumDate variable accessible outside the class. As a next step you can make a property in MDDatePickerDialog to set maximum date in the same way it sets minimum date.
A part from MDDatePicker.m file
- (void)setMinimumDate:(NSDate *)minimumDate {
self.calendar.minimumDate = minimumDate;
}
P.S. Remember to handle the date validations like date should be valid and maximum date should not be earlier than minimum date etc.
Hope that helps!
You just have to add date whatever you want to make maximum, here I have to make only a week date should be selected from the current date, So here is the code which I've written, where you show the date picker just add one line:
- _datePicker.maximumDate = [[NSDate date] dateByAddingTimeInterval:60*60*24*7]; ;
After that search this method into MDCalender.m file and replace with this code.
- (BOOL)shouldSelectDate:(NSDate *)date {
BOOL result;
if ([self.maximumDate timeIntervalSince1970] >= date.timeIntervalSince1970 ) {
result =
(date.timeIntervalSince1970 >= self.minimumDate.timeIntervalSince1970);
return result;
}
return result;
}
It worked for me. Thanks

Color not changing of Calendar Item

I am using CKCalendar for making calendar . I want to change color of date which is in my Array. I am using present Array
present =[[NSMutableArray alloc]init];
NSDate *now = [NSDate date];
int daysToAdd = 1;
NSDate *newDate1 = [now dateByAddingTimeInterval:60*60*24*daysToAdd];
[present addObject:newDate1];
The value present Array is showing "2015-09-03 07:37:30 +0000"
When i am apply the method for change the color.
- (void)calendar:(CKCalendarView *)calendar configureDateItem:(CKDateItem *)dateItem forDate:(NSDate *)date {
// TODO: play with the coloring if we want to...
NSLog(#"%#",date); // 2015-09-03 18:30:00 +0000
NSLog(#"%#",present); //"2015-09-03 07:37:30 +0000"
if ([present containsObject:date]) {
dateItem.backgroundColor = [UIColor redColor];
}
}
They show diffrent value so they not enter in my Code . Please Help . I am stuck .Any help would be apperciated.

iOS - Comparing NSDate with another NSDate

i know how to get difference between two NSDate as follow
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:anyPreviousDate];
and i know it will return me NSTimeInterval in positive seconds. what I want to know is what it will return if my anyPreviousDate is greater than [NSDate date] i.e. anyPreviousDate has not been passed it will come in future.
just curious if anybody has done that before.
Thanks in advance.
I have found another very nice approach to do the same...
here is the code, i thought to share it with stackoverflow.
Cocoa has couple of methods for this:
in NSDate
– isEqualToDate:
– earlierDate:
– laterDate:
– compare:
When you use - (NSComparisonResult)compare:(NSDate *)anotherDate ,you get back one of these:
The receiver and anotherDate are exactly equal to each other, NSOrderedSame
The receiver is later in time than anotherDate, NSOrderedDescending
The receiver is earlier in time than anotherDate, NSOrderedAscending.
example:
NSDate * now = [NSDate date];
NSDate * mile = [[NSDate alloc] initWithString:#"2001-03-24 10:45:32 +0600"];
NSComparisonResult result = [now compare:mile];
NSLog(#"%#", now);
NSLog(#"%#", mile);
switch (result)
{
case NSOrderedAscending: NSLog(#"%# is in future from %#", mile, now); break;
case NSOrderedDescending: NSLog(#"%# is in past from %#", mile, now); break;
case NSOrderedSame: NSLog(#"%# is the same as %#", mile, now); break;
default: NSLog(#"erorr dates %#, %#", mile, now); break;
}
[mile release];
if([previousDate compare:[NSDate date]] == NSOrderedDescending){
// Previous date is greater than current date.i.e. previous date
//is still to come
}else{
//Previous date is smaller then current date.i.e. previous date
//has passed.
}
compare method of NSDate object returns NSComparisonResult, which is an enum.
NSComparisonResult has following values.
NSOrderedSame is returned if left and right operands are equal
NSOrderedAscending is returned if left operand is smaller than the right operand
NSOrderedDescending is returned if ft operand is greater than the right operand
If anyPreviousDate is actually ten seconds in the future, then your code will return -10.0. It happens quite often that you define NSDates that are some time in the future (for example to do something one minute from now), so this isn't unusual at all.
this's a screenshot to see
NSDate * savedDate = [recordsDic[record.transactionId] modifiedDate];
NSDate * newDate = record.modifiedDate;
NSComparisonResult comparisonResult = [newDate compare:savedDate];
NSTimeInterval timeInterval = [newDate timeIntervalSinceDate:savedDate];
NSLog(#"\nsavedDate: %# \nnewDate : %# \n===> timeInterval: %f",savedDate,newDate,timeInterval);
if (comparisonResult == NSOrderedSame) {
NSLog(#"they are same!!!!");
} else {
NSLog(#"they are NOT same!!!!");
}
Console log:
2019-04-11 17:26:47.903059+0800 xxxxx[19268:24419134]
savedDate: Thu Apr 11 15:47:23 2019
newDate : Thu Apr 11 15:47:23 2019
===> timeInterval: 0.000365
2019-04-11 17:26:47.903193+0800 xxxxx[19268:24419134] they are NOT same!!!!
Can you believe this!? but That's true, I spent almost a whole day figuring this out. cause this won't consistently happen!!!
so I strongly recommend:
1. Do NOT use instance method "- (NSComparisonResult)compare:(NSDate *)other;" to compare, you would see something really wired and you can not figure out.
2. timeIntervalSinceDate is more precise.

My NSDate countdown timer changes when I change views

I have a countdown timer from the current date until 10 minutes have passed.
It counts down completely fine when I'm on the view, but when I change views and come back, then the timer stops, could anybody point me in the right direction?
-(void)updateCountdown {
dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"YYYY-MM-dd-HH-mm-ss"];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSUInteger unitFlags = NSMinuteCalendarUnit|NSSecondCalendarUnit;
NSDateComponents *dateComponants = [calendar components:unitFlags fromDate:startingDate toDate:endingDate options:0];
NSInteger minutes = [dateComponants minute];
NSInteger seconds = [dateComponants second];
NSString *countdownText = [NSString stringWithFormat:#"Free Check: %ld:%ld", (long)minutes, (long)seconds];
timeLabel.text = countdownText;
NSLog (#"Startdate is %#", startingDate);
NSLog(#"Enddate is %#", endingDate);
//Attempt at saving the time but I guess this only saves the text?
NSString * saveStringTime = timeLabel.text;
NSUserDefaults * defaultsTime = [NSUserDefaults standardUserDefaults];
[defaultsTime setObject:saveStringTime forKey:#"saveStringTime"];
[defaultsTime synchronize];
[self performSelector:#selector(updateCountdown) withObject:nil afterDelay:1];
}
I think I need something in my ViewDidLoad to get whatever time it was and put that back in?
Thank you
You have to get the "savedStringTime" in viewWillAppear to resume from the "savedTime". Since viewDidLoad will get invoked only if the view is loaded to memory, viewDidLoad will not get invoked when the user navigates back to the same view(since view is still in memory).
To get proper working, Invoke your method to save the time in "viewWillDisappear" and in "viewWillAppear" check if the "savedStringTime" is available, if yes then resume it or else start a fresh counter.

Resources