I have a simple method that determines the NSDate from a string like "NOV 2017". When I step through the method, actualDate has the correct value but nil is passed to the calling method.
The code below was working until recently, I'm on Xcode 9.0 targeting iOS 10 / 11.
Here is the calling method
NSDate *eventDate = [DateClass dateFromMonthYearString:#"NOV 2017"];
Method definition
+(NSDate*)dateFromMonthYearString:(NSString*)monthYearString
{
NSDateFormatter *formatter = [self cachedFormatter];
[formatter setDateFormat:MONTH_YEAR_DATE_FORMAT];
NSDate* actualDate = [formatter dateFromString:monthYearString];
return actualDate;
}
+(NSDateFormatter*) cachedFormatter
{
if (cachedDateFormatter == nil)
{
cachedDateFormatter = [[NSDateFormatter alloc] init];
cachedDateFormatter.locale = [NSLocale currentAppLocale];
}
return cachedDateFormatter;
}
The MONTH_YEAR_DATE_FORMAT is defined as ...
NSString * const MONTH_YEAR_DATE_FORMAT = #"MMM yyyy";
When I print the date object inside the method definition, Xcode prints the date correctly. When I try to 'po' outside the method definition, I just get something like this
(lldb) po eventDate
0x000000012eb048e0
Any thoughts ?
So when I print the values to the console via NSLog, it prints the correct value. Looks like its just the variable display and 'po' commands don't work correctly in X9.1 Weird ??
Related
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!
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
I'm trying to create month strings that look like "Jan", "Feb", "Mar"... Here is my code:
- (NSString *)getMonthNameString:(int)monthNumber {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"MMM"];
NSArray *monthNames = [formatter standaloneMonthSymbols];
NSString *monthName;
if (monthNumber > 0) {
return monthNames[monthNumber - 1];
}
return monthNames[1];
}
So if the month number is 1, I'm expecting the code to provide month name as "Jan" and if it is 2, it has to provide month name as "Feb" and so on. But the problem is that even though I have set the format as MMM, it is still creating month names of type "January", "February" etc instead of "Jan","Feb" etc. How do I sort this out?
Try:
-(NSString*)getMonthNameString:(int)monthNumber
{
NSDateFormatter *formate = [NSDateFormatter new];
[formate setDateFormat:#"MMM"];
NSArray *monthNames = [formate shortMonthSymbols];
NSString *monthName;
if (monthNumber > 0)
{
monthName = [monthNames objectAtIndex:(monthNumber - 1)];
}
return monthName;
}
That's usually not what a NSDateFormatter is for - it is for converting real dates, and not just month numbers.
If you want to stick with it, I suggest
-(NSString*)getMonthNameString:(int)monthNumber {
NSDateFormatter *formatter = [NSDateFormatter new];
return formatter.shortMonthSymbols[monthNumber-1];
}
I see no benefit in the extra check for > 0. This just masks programming errors. You might want to add an assertion to catch that during development. (Why should an invalid number return January anyway?)
Creating formatters is expensive, though - you might want to reuse the same instance over and over again.
Or just access an array directly, i.e.
-(NSString*)getMonthNameString:(int)monthNumber {
return #[#"Jan", #"Feb", ...][monthNumber-1]; // write up to December of course
}
standaloneMonthSymbols is a property of NSDateFormatter. I don't think it uses the dateFormat you've set. Try using shortStandaloneMonthSymbols property instead (or veryShortStandaloneMonthSymbols if you just need one letter symbol).
tahavath is right. Specifically, you want to use the shortStandaloneMonthSymbols property to get it to print "Jan" or "Feb" etc.
Try the following:
-(NSString*)getMonthNameString:(int)monthNumber
{
NSDateFormatter *formate = [NSDateFormatter new];
[formate setDateStyle:NSDateFormatterMediumStyle];
[formate setDateFormat:#"MMM"];
NSArray *monthNames = [formate standaloneMonthSymbols];
NSString *monthName;
if (monthNumber > 0)
{
monthName = [monthNames objectAtIndex:(monthNumber - 1)];
}
return monthName;
}
Check your code #Karuppu MGR
-(NSString*)getMonthNameString:(int)monthNumber
{
NSDateFormatter *formate = [NSDateFormatter new];
[formate setDateFormat:#"MMM"];
NSArray *monthNames = [formate standaloneMonthSymbols];
NSString *monthName;
if (monthNumber > 0 && monthNumber<13)
{
monthName = [monthNames objectAtIndex:(monthNumber - 1)];
// your process is right but , here you have attached "return value " so every time return the monthNames array value.
}
return monthName; // if you pass zero or greathan twelve monthName return nil value
}
the application crashed when calling this function, how ever in iPhone it works fine , but in iPad the application crashes and say
note: i'm using ActionSheetDatePicker library
Thread 1: EXC_BAD_ACCESS (cod = 1 , address = 0x9e...)
when i debug i found selectedDate is nil in iPad , but works fine in iPhone
#pragma mark - Implementation
- (void)dateWasSelected:(NSDate *)selectedDate element:(id)element {
// self.selectedDate = selectedDate;
//may have originated from textField or barButtonItem, use an IBOutlet instead of element
//DATE TEXT FIELD HERE
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"YYYY-MM-dd"];
//Optionally for time zone converstions
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"..."]];
NSString *stringFromDate = [formatter stringFromDate:selectedDate];
self.textFieldBirthDate.text = stringFromDate ;
birthDate = stringFromDate ;
//"YYYY-MM-DD" the birthdate format
}
The git hub code which you provided is working fine for me and I did debug the code.
When user Taps on done button (After selecting the date) below code will be executed.
- (void)notifyTarget:(id)target didSucceedWithAction:(SEL)action origin:(id)origin {
if ([target respondsToSelector:action])
objc_msgSend(target, action, self.selectedDate, origin);
else
NSAssert(NO, #"Invalid target/action ( %s / %s ) combination used for ActionSheetPicker", object_getClassName(target), (char *)action);
}
Now here make sure you are getting value for self.selectedDate , if you are not getting then please do check that you are getting a breakpoint to below code when you just select a date by scrolling.
- (void)eventForDatePicker:(id)sender {
if (!sender || ![sender isKindOfClass:[UIDatePicker class]])
return;
UIDatePicker *datePicker = (UIDatePicker *)sender;
self.selectedDate = datePicker.date;
}
These codes are present in file
ActionSheetDatePicker.m
If you are getting the breakpoint here then make sure you are saving the date .Once you do check this the problem will be resolved.
Regards,
Anil
I'm attempting to initialize a custom class in my view controller to manage the data. Unfortunately the app crashes during the loading. I'm running Xcode 5.02 with the lldb debugger. The error I get is
Thread 1: EXC_BAD_ACCESS (code=2, address=0xbf7ffffc)
The error shows up on the first line (-(void)...) of the function
-(void)setDateOfErgPiece:(NSDate *)date
{
self.dateOfErgPiece = date;
if(self.dateOfErgPiece) {
// Date Formatter. So Date is displayed correctly
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
// Set value
self.dateOfErgPieceString = [NSString stringWithFormat:#"%#", [dateFormatter stringFromDate:self.dateOfErgPiece]];
}
}
That method is called when the object is initialized by
-(id)initWithDate:(NSDate *)date
{
self = [super init];
if(self) {
[self setDateOfErgPiece:date];
}
return self;
}
The (NSDate *)date value in the above init method is received from this method
-(ErgNewDataEntryLogic *)ergPieceData {
if(!_ergPieceData) _ergPieceData = [[ErgNewDataEntryLogic alloc] initWithDate:[NSDate date]];
return _ergPieceData;
}
What is causing this error? If you need more information I'd be happy to provide it. Thank you so much!
I don't know if this is exactly the problem or not, but this is certainly a major problem:
-(void)setDateOfErgPiece:(NSDate *)date {
self.dateOfErgPiece = date;
// ...
self.dateOfErgPiece = date; is exactly equivalent to [self setDateOfErgPiece:date];.
So, as the first line of the method, the method is calling itself. Infinite recursion.
This should be changed to the following...
-(void)setDateOfErgPiece:(NSDate *)date {
_dateOfErgPiece = date;
// ...
The other references to self.dateOfErgPiece within the method seem to be okay, because they look to be calling the getter:
[self dateOfErgPiece];