NSDateFormatter in loop - objective-c

I am having some issues with the following function. I have a dictionary with an array of date strings. I would like to loop through them and generate an NSDate object for each string. An example of the date string would be 20Z01NOV2011, where 20Z indicates 8:00 Zulu time, followed by the day,month, year.To make the date extraction easier, I remove the Z and insert a space.
The date formatter seems to work fine the first loop iteration, however fails on the subsequent iterations, however the input string format seems to be fine. Im not sure if there is a memory issue, and the string or formatter needs to be cleared, but I could use a hand correcting it.
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"HH ddMMMyyyy"];
NSMutableArray *tempDates = [[NSMutableArray alloc] initWithCapacity:[[dict objectForKey:#"time"] count]];
NSMutableArray *tempDateStrings = [[NSMutableArray alloc] initWithCapacity:[[dict objectForKey:#"time"] count]];
for (int i=0; i < [[dict objectForKey:#"time"] count]; ++i) {
NSString *dateString = [[[dict objectForKey:#"time"] objectAtIndex:i] stringByReplacingOccurrencesOfString:#"Z" withString:#" "];
NSDate *date = [timeFormatter dateFromString:dateString];
[tempDates addObject:date];
[timeFormatter setDateFormat:#"EEE h:mm a"];
[tempDateStrings addObject:[timeFormatter stringFromDate:date]];
}
[dict setObject:tempDateStrings forKey:#"dateStrings"];
[dict setObject:tempDates forKey:#"dateObjects"];

Side note, I think you should remove the index from the iteration entirely:
Also, you're resetting the formatter inside the loop…
for (NSString *dateString in [dict objectForKey:#"time"]) {
dateString = [dateString stringByReplacingOccurrencesOfString:#"Z" withString:#" "];
NSDate *date = [timeFormatter dateFromString:dateString];
[tempDates addObject:date];
[timeFormatter setDateFormat:#"EEE h:mm a"]; // RESETING DATE FORMAT - SECOND ITERATION WILL FAIL
[tempDateStrings addObject:[timeFormatter stringFromDate:date]];
}
I suspect you want two formatters, ONE to read the string input, and a SECOND to output the value into the format you like.

It fails on subsequent iterations because you MODIFIED THE FORMAT near the bottom of the loop. What you probably want is two separate formatters, one for one format and one for the other, so you don't have to switch formats back and forth.

Related

Why does this function return the same value regardless of input?

I have a method that formats a date string. I've encountered an issue where it returns only the formatted version of the first NSString I pass to it..
Code:
self.lastUpdatedLabel.text = [self convertTime:lastupdated];
self.expiryDate.text = [self convertTime:expiryDate];
Method
- (NSString *)convertTime:(NSString *)date{
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"HH:mm - dd/MM/yyyy"];
[timeFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
date = [timeFormatter stringFromDate:[[NSDate alloc]init] ];
return date;
}
Both lastUpdatedLabel and expiry date are set to the value of expiryDate. Surely the method runs every time it is called, producing a different output as the input is different
It looks like you need to update your code to use your argument, date.
As people have mentioned in comments, you are using the current time, [[NSDate alloc] init] instead of the date that was passed in.
If lastUpdated and expiryDate are NSDates, then this will work.
- (NSString *)convertTime:(NSDate *)date{
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"HH:mm - dd/MM/yyyy"];
[timeFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
return [timeFormatter stringFromDate:date];
}
If lastUpdated and expiryDate are NSStrings, which is what it looks like you have, then you need to convert your NSStrings to NSDates, using an NSDateFormatter that understands the format of the NSString that you have ... and then pass that NSDate to the code above to create a properly formatted string as output.

Detaching a string into two using objective c [duplicate]

This question already has answers here:
Separate 1 NSString into two NSStrings by whiteSpace
(2 answers)
Closed 10 years ago.
I am getting the date from data base in this format, '01/02/2013 17:00'. I have to detach the date and time and put it in separate columns in the nstableview (date in date column and time in time column). How should i do this?
You can:
NSArray *dateAndTime = [#"01/02/2013 17:00" componentsSeparatedByString:#" "];
This if you are certain about that format. Otherwise you should be careful and rely on something like NSDateFormatter.
NSString *dateTime = #"01/02/2013 17:00";
NSArray *strings = [dateTime componentsSeparatedByString:#" "];
The array strings will now look like...
[
#"01/02/2013",
#"17:00"
]
If you want to be able to change to time format, or want more control over the times etc. I recommend a NSDateFormatter..
NSString *dateString = #"'01/02/2013 17:00";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd/MM/YYYY HH:mm"];
NSDate *date = [formatter dateFromString:dateString];
[formatter setDateFormat:#"dd/MM/YYYY"];
NSString *newDateString = [formatter stringFromDate:date];
[formatter setDateFormat:#"HH:mm"];
NSString *newTimeString = [formatter stringFromDate:date];

Creating NSDate from NSString.

I have stored a date in a text file, and I can read it out properly. The output for this string is
"6:00 PM"
Just like that. However, when I do:
//First, set the first datePicker
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
NSString *breakfastTimeStartLocation = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"breakfastTimeStart.txt"];
NSString *time = [NSString stringWithContentsOfFile:breakfastTimeStartLocation encoding:NSUTF16StringEncoding error:nil];
NSLog(#"Loaded time is %#", time);
NSDate *startDate = [dateFormatter dateFromString:time];
NSLog(#"Start Date = %#", startDate);
In this, time returns the "6:00 PM", but startDate returns "(null)"
I must be missing something, why in the world does this not work?
Thanks.
I believe the issue is that you never set a Date Format. Even if this is not the only problem it would probably be one. Try something like:
[dateFormatter setDateFormat:#"MM/dd/YYYY"];
That's not the right way to init an NSDateFormatter, the designated initializer is initWithDateFormat:allowNaturalLanguage:
Thus:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]
initWithDateFormat:#"h:mm a" allowNaturalLanguage:NO];

Problems with Creating an NSDate object from a ISO 8601 string

I'm having problems converting a string into a NSDate object and I'm not sure why.
NSString* tester= #"2012-11-26T10:20:40.187";
NSLog(#"", tester); //Print the Date String
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
NSDate *date = [formatter dateFromString:tester]; //Store the date
NSDateFormatter *output = [[NSDateFormatter alloc] init];
[output setDateStyle:NSDateFormatterMediumStyle];
NSLog(#"DATE OBJECT:%#\nDATE STRING: \"%#\"", [output stringFromDate:date]); //Print the NSDate object and the string
But all I seem to get is:
DATE OBJECT:(null)
DATE STRING: "2012-11-26T10:20:40.187"
I figure it has something to do with the .187 but I'm not sure. I'm sorry if this is a duplicate but I couldn't figure this out.
Thank you very much in advance!
The abbrevation for milliseconds is "S"not Z which is TimeZone.
It seems that you have read the correct document where that example is from, but
you missed the link to the Unicode Technical Standard #35.
See NsDateFormatter Docu, search for "Formatters in Mac OS X v10.4 use version tr35-4."
try that below:
[formatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSS"];
See also NSDateFormatter Question

Getting date info into an array in Objective-C Cocoa framework

I have a function that returns an array to hold date info.
- (NSArray*) getTodayArray
{
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"YYYY"];
NSString *year = [dateFormatter stringFromDate:today];
[dateFormatter setDateFormat:#"MM"];
NSString *month = [dateFormatter stringFromDate:today];
[dateFormatter release];
NSArray *res = [NSArray arrayWithObjects: year, month, nil];
return res;
}
Q1 : Is there any easy way to get all the info (year, month, date, hour, minute ...) in an array not using setDateFormat over and over again?
Q2 : Is there a way so that I can access the content of array using res['year'] or similar? I mean using dictionary?
Q3 : Do I need to release NSArray *res in the caller of this function?
A1: You can do smth like this:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"YYYY|MM"];
NSArray* d_arr = [[dateFormatter stringFromDate: [NSDate date]] componentsSeparatedByString: #"|"];
A2: Use NSDictionary:
[NSDictionary dictionaryWithObjectsAndKeys: [d_arr objectAtIndex: 0], #"year", [d_arr objectAtIndex: 1], #"month", nil]
A3: return value is autoreleased. you don't need to release it.
#prosseek
1 - I dont think you have another choice to get the year, month, date, hour, minute ... from NSDate other than this.(I am not sure about it though.)
2 - you can access the objects in the dictionary in the above format but something more like objective-c style. like this
[dateDictionary obectForKey:#"year"];
but you need to define the dictionary in that format
like this
NSDictionary *dateDictionary = [NSDictionary dictionaryWithObjects:year,min,hr,nil forKeys:#"year", #"min", #"hour", nil];
3 - no you dont need to release or autorelease the NSArray in the above method . but i think you need to retain it in the array that is receiving res array if you want to use it after a while.
Why don't you just use a NSArray of NSDates?
You can probably get all of your desired functionality out of its plethora of functions.
A1: You could dump it all out into a string, but then you'd have to parse the string, which wouldn't be any easier.
A2: You could do that if you used an NSDictionary instead of an NSArray.*
A3: No, it's already autoreleased.
* Why don't you write a category for NSDate instead?
NSDate+Convenience.h
#interface NSDate (Convenience)
- (NSInteger)year;
- (NSInteger)month;
#end
NSDate+Convenience.m
#implementation NSDate (Convenience)
- (NSInteger)year {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"YYYY"];
NSString *myYear = [dateFormatter stringFromDate:self];
[dateFormatter release];
return myYear;
}
- (NSInteger)month {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM"];
NSString *myMonth = [dateFormatter stringFromDate:self];
[dateFormatter release];
return myMonth;
}
#end
Just #include NSDate+Convenience.h wherever you want to use your handy date and month accessors. All of your NSDate instances will then get them:
NSDate *myDate = [NSDate date];
NSLog(#"%ld %ld", [myDate year], [myDate month]);
No need for loosely-typed NSArrays or NSDictionaries to store this stuff.
(Note you could modify the above code to use a shared NSDateFormatter.)
Q1: Not an array, but you can use -[NSCalendar components:fromDate:] to get an NSDateComponents object. You can use it directly or build an array from it, if that is your preference.
Q2: No, but if you return an NSDateComponents object, then you can use -year, -month, etc methods on it.
Q3: No, you don't need to release it in this method or the caller, unless the caller retains it (which may be desirable).
You're looking for the NSDateComponents class. You'll need to create an NSCalendar object first, then call the components:fromDate: method to get the DateComponents object, after which you can access the object's month, year etc. properties.
Not quite sure what you want here. As it stands, the array cannot be accessed in the manner you describe, though if you want you could always create a dictionary and assign values for keys such as 'month' or 'year'. However, it might just be easier to return the DateComponents object, and access its properties.
No, there is no need to release the NSArray. You constructed it using the NSArray class method, which is already autoreleased.