Parse Time From NSDate - ios

I am trying to get the time from a string that looks like #"2016-05-12T16:25:55.000Z". I have tried something like this:
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = #"HH:mm";
formatter.timeZone = [NSTimeZone systemTimeZone];
NSDate *serverDate = [formatter dateFromString:dateString];
NSString* time = [formatter stringFromDate:serverDate];
NSLog(#"Time: %#", time);
But my serverDate is returning null. I'm not sure what I am doing wrong.

When you create an NSDate from an NSString, the date format has to completely match the entire string.
But it seems your goal is to get the time as a string. So just get the substring:
NSString *time = [dateString substringWithRange:NSMakeRange(11, 5)];
Of course this doesn't deal with the timezone in any way. If you wish to parse the original string into an NSDate and then get the time from that date, all with needed timezone adjustments, then you need two date formats. One to parse the original string into an NSDate, and the 2nd (the one you already have), to generate the new string with the desired output (the time in this case).

You can set the dateFormat property of your formatter to: #"yyyy-MM-dd'T'HH:mm:ssZ", and then get the time value using NSDateComponents.

First convert your date to NSDate
+ (NSDate *) convertDateToNSDateWithGivenFormat: (NSString *) dateStr Format:(NSString*) format
{
NSDateFormatter *dateFormatterDate = nil;
NSDate *dateonly = nil;
if (dateFormatterDate == nil) {
dateFormatterDate = [[NSDateFormatter alloc] init];
[dateFormatterDate setDateFormat:format];
}
dateonly = [dateFormatterDate dateFromString:[NSString stringWithFormat:#"%#", dateStr]];
return dateonly;
}
then use the NSDate variable to split date and time
+ (NSString *) GetFormattedTimeStringForGivenDate:(NSDate *) date
{
NSString *retStr = nil;
NSDate *now = date;
NSDateFormatter *dateFormatterDateOnly = nil;
NSDateFormatter *dateFormatterTimeOnly = nil;
if (dateFormatterDateOnly == nil) {
dateFormatterDateOnly = [[NSDateFormatter alloc] init];
[dateFormatterDateOnly setDateFormat:#"MM/dd/yyyy"];
}
if (dateFormatterTimeOnly == nil) {
dateFormatterTimeOnly = [[NSDateFormatter alloc] init];
[dateFormatterTimeOnly setDateFormat:#"hh:mm:ss:a"];
}
//if you need date use this
//retStr = [NSString stringWithFormat:#"%#", [dateFormatterDateOnly stringFromDate:now]];
retStr = [NSString stringWithFormat:#"%#", [dateFormatterTimeOnly stringFromDate:now]];
return retStr;
}
Here is example. You can change the Format as per your need:
NSDate *myDt = [MyClass convertDateToNSDateWithGivenFormat: #"2016-05-12T16:25:55" Format:#"yyyy-MM-dd'T'HH:mm:ss"];
NSString *str = [MyClass GetFormattedTimeForGivenDate:myDt];

Related

How to Get Date, Hour, Minute and Second in Objective-c from Timestamp "2017-04-30T14:30+00:00(GMT)"?

I'm new in iOS(Objective-c) coding and I'm stuck at timestamp.
I'm getting timestamp while JSON parsing ie.2017-04-30T14:30+00:00(GMT). How to get date, hour, minute and second from this timestamp?? I'm getting this format in GMT so, is it possible to convert it into "IST"? How?
Date Format Patterns
A date pattern is a string of characters, where specific strings of characters are replaced with date and time data from a calendar when formatting or used to generate data for a calendar when parsing. The following are the characters used in patterns to show the appropriate formats for a given locale. The following are examples:
- (NSString *)curentDateStringFromDate:(NSDate *)dateTimeInLine withFormat:(NSString *)dateFormat {
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:dateFormat];
NSString *convertedString = [formatter stringFromDate:dateTimeInLine];
return convertedString;
}
Use it like below:
NSString *dateString = [self curentDateStringFromDate:[NSDate date] withFormat:#"dd-MM-yyyy"];
NSString *timeString = [self curentDateStringFromDate:[NSDate date] withFormat:#"hh:mm:ss"];
NSString *hoursString = [self curentDateStringFromDate:[NSDate date] withFormat:#"h"];
In the Foundation framework, the class to use for this task (in either direction) is NSDateFormatter Refer here
The code below convert GMT to IST.
NSString *inDateStr = #"2000/01/02 03:04:05";
NSString *s = #"yyyy/MM/dd HH:mm:ss";
// about input date(GMT)
NSDateFormatter *inDateFormatter = [[NSDateFormatter alloc] init];
inDateFormatter.dateFormat = s;
inDateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSDate *inDate = [inDateFormatter dateFromString:inDateStr];
// about output date(IST)
NSDateFormatter *outDateFormatter = [[NSDateFormatter alloc] init];
outDateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"IST"];
outDateFormatter.dateFormat = s;
NSString *outDateStr = [outDateFormatter stringFromDate:inDate];
// final output
NSLog(#"[in]%# -> [out]%#", inDateStr, outDateStr);

How to get local time with NSDateFormatter (parsing from ICS file)

I'm trying to get the local time from an NSDate and it is only outputting the +0000 timezone. I'm parsing the information from an ICS file and then converting the string (looks like 20131001T114445Z) to a date with NSDateFormatter but for some reason I can't change it to the user's local time.
Here is the relevent code -
+(ISParseICS*) icsParser
{
if( !fetcher ) {
fetcher = [ISParseICS new];
fetcher.dateFormatter = [[NSDateFormatter alloc] init];
[fetcher.dateFormatter setDateFormat:#"yyyyMMdd HHmmss"];
NSLog(#"Created new singleton fetcher");
}
return fetcher;
}
Code below within -(NSMutableArray *)fetchPassesSync
// Extract date/time
NSString *unformattedEndDateTimeString;
NSDate *endDate;
eventScanner = [NSScanner scannerWithString:event];
[eventScanner scanUpToString:#"DTEND:" intoString:nil];
[eventScanner scanUpToString:#"\n" intoString:&unformattedEndDateTimeString];
unformattedEndDateTimeString = [unformattedEndDateTimeString stringByReplacingOccurrencesOfString:[NSString stringWithFormat:#"DTEND:"] withString:#""];
NSLog(#"This is unformattedEndDateTimeString: %#", unformattedEndDateTimeString);
endDate = [self dateFromString:unformattedEndDateTimeString];
NSLog(#"End date - %#", endDate);
...and the last piece:
-(NSDate *)dateFromString:(NSString *)dateString {
dateString = [dateString stringByReplacingOccurrencesOfString:#"T" withString:#" "];
dateString = [dateString stringByReplacingOccurrencesOfString:#"Z" withString:#""];
NSDate *date = [self.dateFormatter dateFromString:dateString];
// NSLog(#"The output date: %#", date);
return date;
}
I'm pretty new to programming and I hope I asked the question correctly. Thanks in advance.
Edit: What I get out of all this code is it takes the string "20131001T114445Z" and outputs like this "2013-10-01 11:44:45 +0000"
Try this:-
NSString *dateStr = #"20131001T114445Z";
// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
[dateFormat setDateFormat:#"yyyyMMdd'T'hhmmss'Z'"];
NSDate *date = [dateFormat dateFromString:dateStr];
// Convert date object to desired output format
[dateFormat setDateFormat:#"yyyy-MM-dd hh:mm:ss Z"];
dateStr = [dateFormat stringFromDate:date];
NSLog(#"%#",dateStr);
[dateFormat release];

How to compare current system time with an array of times

I am using the below code to try and use current system time to tell me the next time in the array. All it logs out is the last number in the array. I have searched, and this is how I ended up where I am, but could never get it to work just right. Thanks
self.array = #[#"00:15", #"01:35, "#"05:30", #"06:10", #"07:05", #"07:55", #"08:45", #"09:35", #"10:40", #"11:25", #"12:20", #"13:10", #"14:05", #"15:00", #"15:45", #"16:40", #"17:30", #"18:20", #"19:20", #"20:10", #"21:00", #"22:05", #"22:55"];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"HH:mm"];
NSDate *formattedCurrentDate = [dateFormat dateFromString:[dateFormat stringFromDate:[NSDate date]]];
for(NSString *stringTime in self.array) {
NSDate *dateFromString = [dateFormat dateFromString:stringTime];
if([formattedCurrentDate earlierDate:dateFromString]) {
self.nextTime.text = stringTime;
}
}
Your code is behaving exactly as it should, you are having it return an earlier time than the current time, which means every single time is assigned to self.nextTime.text, but you only see the very last assignment, which is the last item in the array.
Further more your if statement always returns true if executed correctly, so you will always get true unless you provide an object that is not an NSDate.
Here is the correct way of getting what you would like without having to worry about ordering your array.
NSArray *array = #[#"16:40", #"05:30", #"06:10", #"07:05", #"07:55", #"08:45", #"09:35", #"10:40", #"11:25", #"12:20", #"13:10", #"14:05", #"15:00", #"15:45", #"16:40", #"17:30", #"18:20", #"19:20", #"20:10", #"21:00", #"22:05", #"22:55", #"23:55", #"01:35"];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"HH:mm"];
NSDate *formattedCurrentDate = [dateFormat dateFromString:[dateFormat stringFromDate:[NSDate date]]];
NSDate *laterDate;
NSDate *closestDate;
for(NSString *stringTime in array) {
NSDate *dateFromString = [dateFormat dateFromString:stringTime];
laterDate = [formattedCurrentDate laterDate:dateFromString];
if(![laterDate isEqualToDate:formattedCurrentDate]){
closestDate = [laterDate earlierDate:closestDate];
}
}
NSLog(#"Closest Date: %#", [dateFormat stringFromDate:closestDate] );
NSArray *array = #[#"23:15", #"01:35", #"05:30", #"06:10", #"07:05", #"07:55", #"08:45", #"09:35", #"10:40", #"11:25", #"12:20", #"13:10", #"14:05", #"15:00", #"15:45", #"16:40", #"17:30", #"18:20", #"19:20", #"20:10", #"21:00", #"22:05", #"22:55", #"23:55"];
NSMutableArray *datesArray = [[NSMutableArray alloc] init];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"HH:mm"];
//Convert all strings to dates
for (NSString *str in array)
{
NSDate *formattedCurrentDate = [dateFormat dateFromString: str];
[datesArray addObject:formattedCurrentDate];
}
//Sort dates.
NSArray *sortedArray = [datesArray sortedArrayUsingSelector:#selector(compare:)];
NSString *date = [dateFormat stringFromDate:[NSDate date]];
NSDate *formattedTodatDate = [dateFormat dateFromString:date];
//Print the desired date
for(NSDate *stringTime in sortedArray)
{
if([formattedTodatDate compare:stringTime] == NSOrderedAscending)
{
NSLog(#"Result is %#", [dateFormat stringFromDate:stringTime]);
break;
}
}
Try the above code. I just followed what others have mentioned with sorting dates.
If you want a more generic solution, that doesn't depend on the order of the array, you could use the code below:
NSArray *array = #[#"02:25", #"01:35", #"05:30", #"06:10", #"07:05", #"07:55", #"08:45", #"09:35", #"10:40", #"11:25", #"12:20", #"13:10", #"14:05", #"15:00", #"15:45", #"16:40", #"17:30", #"18:20", #"19:20", #"20:10", #"21:00", #"22:05", #"22:55", #"23:55"];
NSDateFormatter *dateFormat = [NSDateFormatter new];
[dateFormat setDateFormat:#"HH:mm"];
NSDate *formattedCurrentDate = [dateFormat dateFromString:[dateFormat stringFromDate:[NSDate date]]];
NSTimeInterval currentInterval = [formattedCurrentDate timeIntervalSince1970];
NSTimeInterval smallerInterval = CGFLOAT_MAX;
for(NSString *stringTime in array) {
NSDate *dateFromString = [dateFormat dateFromString:stringTime];
NSTimeInterval dateFromStringInterval = [dateFromString timeIntervalSince1970];
NSTimeInterval actualInterval = (dateFromStringInterval - currentInterval);
if(actualInterval > 0 && actualInterval < smallerInterval){
smallerInterval = actualInterval;
self.nextTime.text = stringTime;
}
}
This code is getting the closest next hour of the current hour, independent of it's index inside the array. And doesn't require more allocations or any sorting of arrays, like #Sandeep solutions (that do works).
Explaining:
The actualInterval is getting the difference in seconds between all dates and the current date. This variable (which is a double, actually) will only be positive to future hours (past hours will be negative).
So, all the code is doing is getting the smaller difference between future hours. This is, I think, the best solution to this case.
Hope this helped.
if your function works fine.
change:
for(NSString *stringTime in self.array) {
NSDate *dateFromString = [dateFormat dateFromString:stringTime];
if([formattedCurrentDate earlierDate:dateFromString]) {
self.nextTime.text = stringTime;
}
}
to:
for(NSString *stringTime in self.array) {
NSDate *dateFromString = [dateFormat dateFromString:stringTime];
if([formattedCurrentDate compare:dateFromString] == NSOrderedAscending) {
self.nextTime.text = stringTime;
break;
}
}

NSDate conversion issue when input NSDate format is unknown and separate Date and Time [duplicate]

This question already has answers here:
Objective-C String(yyyy-mm-dd) to NSDate
(3 answers)
Closed 9 years ago.
I get null date even when the string that I pass has a date as shown below:-
Generic input Date Format is "MM/dd/YYYY hh:mm a"
NSString input Date can be one of the following: "12/1/2012" , "12/1/2012 01:43 am" , "01:43 am"
Expected output which I am trying is that , it must print date if it exists in input string and time must be printed out if it exists in the input string.
Input:-
[self testDate:#"12/1/2012"]
Code:-
-(void) testDate:(NSString*) str{
NSDateFormatter *formatter=[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM/dd/yyyy hh:mm a"];//My Generic Date Format
self.dateTest=[formatter dateFromString:str];
[self printDate:self.dateTest];
}
-(void) printSeparatedDateAndTime:(NSDate*) date{
NSDateFormatter *dateF=[[NSDateFormatter alloc] init];
[dateF setDateFormat:#"MM/dd/yyyy"];
NSString *dateStr=[dateF stringFromDate:date];
NSLog(#"Date= %#",dateStr);
[dateF setDateFormat:#"hh:mm a"];
NSString *timeStr=[dateF stringFromDate:date];
NSLog(#"Time= %#",timeStr);
}
Output Date:-
Date= (null)
Time= (null)
Input can be in any format, ex
input
"12/1/2012"
output
date="12/1/2012"
time=null
input
"12/1/2012 01:43 am"
output
date="12/1/2012"
time=01:43 am
input
"01:43 am"
output
date=null
time="01:43 am"
One can get a different answer here Objective-C String(yyyy-mm-dd) to NSDate. This refers to answer if date format set is wrong.
In my case date format is correct. But it might have only date, only time or both of them.
To separate date and time from a String one can refer here ios4 - splitting a date and time from a string into two separate strings, but it does not have a checked answer or a valid answer.
Remove hh:mm a and the format can be either "MM/dd/yyyy" or "dd/MM/yyyy".
-(void) testDate:(NSString*) str{
NSDateFormatter *formatter=[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd/MM/yyyy"];
self.dateTest=[formatter dateFromString:str];
[self printDate:date];
}
Your printeDate: will not work as expected since the date created don't have any information about the time and you are trying to show hours and minutes.It will always show 12.00 AM.
If you want to show hours and minutes you need to include that also in your input string.
EDIT : Since dateFormats can be in three formats you need to do a trial and error.
-(void) testDate:(NSString*) str{
NSArray *dateFormats = #[#"dd/MM/yyyy",#"hh:mm a",#"dd/MM/yyyy hh:mm a"];
NSDateFormatter *formatter=[[NSDateFormatter alloc] init];
NSDate *date = nil;
for (NSString *dateFormat in dateFormats) {
[formatter setDateFormat:dateFormat];
date = [formatter dateFromString:str];
if (date) {
break;
}
}
[self printDate:date];
}
OR
-(void) testDate:(NSString*) dateString
{
NSDate *date = nil;
NSError *error = nil;
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeDate
error:&error];
NSArray *matches = [detector matchesInString:dateString
options:0
range:NSMakeRange(0, [dateString length])];
for (NSTextCheckingResult *match in matches) {
if (match.date) {
date = match.date;
break;
}
}
[self printDate:date];
}
EDIT 2 : As it is a requirement to have data/time to nil out. Please try
typedef enum {
ValidDateType = 0,
ValidTimeType = 1,
ValidDateTimeType =2
}ValidType;
- (void)testDate:(NSString*) dateString
{
NSArray *dateFormats = #[#"dd/MM/yyyy",#"hh:mm a",#"dd/MM/yyyy hh:mm a"];
NSDateFormatter *formatter=[[NSDateFormatter alloc] init];
__block NSDate *date = nil;
__block ValidType type = ValidDateType;
[dateFormats enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *dateFormat = (NSString *)obj;
[formatter setDateFormat:dateFormat];
date = [formatter dateFromString:dateString];
if (date) {
type = idx;
*stop = TRUE;
}
}];
[self printDate:date validType:type];
}
- (void)printDate:(NSDate*) date validType:(ValidType)type
{
NSDateFormatter *dateF=[[NSDateFormatter alloc] init];
[dateF setDateFormat:#"MM/dd/yyyy"];
NSString *dateStr=[dateF stringFromDate:date];
[dateF setDateFormat:#"hh:mm a"];
NSString *timeStr=[dateF stringFromDate:date];
dateStr = (type == ValidTimeType)?nil:dateStr;
timeStr = (type == ValidDateType)?nil:timeStr;
NSLog(#"Time= %#",timeStr);
NSLog(#"Date= %#",dateStr);
}
You set the date format to include time: MM/dd/yyyy hh:mm a, but you are not passing any time with you string: 12/1/2012.
Just remove the hh:mm a from the date format :
-(void) testDate:(NSString*) str{
NSDateFormatter *formatter=[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM/dd/yyyy"];
self.dateTest = [formatter dateFromString:str];
[self printDate:self.dateTest];
}
Also I would suggest not using a static date format, just incase you have any non America users. Apple has added NSDateFormatterStyle to make it easy for you to use the user/system selected style of formatting.
-(void) printDate:(NSDate*) date{
NSDateFormatter *dateF=[[NSDateFormatter alloc] init];
dateF.dateStyle = NSDateFormatterMediumStyle;
dateF.timeStyle = NSDateFormatterNoStyle;
NSString *dateStr=[dateF stringFromDate:date];
NSLog(#"Date= %#",dateStr);
dateF.dateStyle = NSDateFormatterNoStyle;
dateF.timeStyle = NSDateFormatterShortStyle;
NSString *timeStr=[dateF stringFromDate:date];
NSLog(#"Time= %#",timeStr);
}

How to parse ISO 8601 using NSDateFormatter with optional milliseconds part

I'm trying to use an NSDateFormatter to parse dates that are in either of these formats
#"2013-02-01T14:21:00"
or
#"2013-02-01T14:21:56.345"
Currently I am using the below method to parse the string and return a date:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
NSDate *date = [dateFormatter dateFromString:dateToFormat];
This works fine for the first style of date but returns nil for a string that includes the milliseconds part.
I suppose I could test for the existence of the milliseconds and strip them but I was wondering if I could change the date format to treat the .SSS as optional?
Thanks for your help
As far as I know there is no way to make optional parameters.
The usual solution is to use two formatters, one for each format.
To decide which formatter to use, you can either
Count the number of characters in the date string (as suggested in Parsing a RFC 822 date with NSDateFormatter)
Just try both formatters and get the first non-nil result.
Since your date formats are similar, you can go with only one formatter and if the date string is too short, append .000 before using the formatter.
The correct approach since iOS 10 is to use ISO8601DateFormatter specifically created to handle all variations of ISO 8601 date strings. Please see the example below:
let date = Date()
var string: String
let formatter = ISO8601DateFormatter()
string = formatter.string(from: date)
let GMT = TimeZone(abbreviation: "GMT")
let options: ISO8601DateFormatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone]
string = ISO8601DateFormatter.string(from: date, timeZone: GMT, formatOptions: options)
And Objective-C version:
NSDate *date = [NSDate date];
NSString *string;
NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init];
string = [formatter stringFromDate:date];
NSTimeZone *GMT = [NSTimeZone timeZoneWithAbbreviation: #"GMT"];
NSISO8601DateFormatOptions options = NSISO8601DateFormatWithInternetDateTime | NSISO8601DateFormatWithDashSeparatorInDate | NSISO8601DateFormatWithColonSeparatorInTime | NSISO8601DateFormatWithTimeZone;
string = [NSISO8601DateFormatter stringFromDate:date timeZone:GMT formatOptions:options];
I wrote an universal parser which dropped milliseconds part.
#implementation JSONModel(NSPAdditions)
- (NSDate *)NSDateFromNSString:(NSString*)string {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
NSArray* parts = [string componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#" T"]];
if ([parts count] <= 1) {
return [formatter dateFromString:string];
}
NSString *part0 = parts[0];
NSAssert([part0 length] == [#"yyyy-MM-dd" length], #"Date format error");
NSString *part1 = parts[1];
if ([part1 length] > [#"HH:mm:ss" length]) {
part1 = [part1 substringToIndex:[#"HH:mm:ss" length]];
}
NSString *fmted = [NSString stringWithFormat:#"%# %#", part0, part1];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
return [formatter dateFromString:fmted];
}
#end

Resources