NSDateFormatter Returning Unexpected Time Values - ios

Can anyone explain to me why the following code returns inconsistent time values? I've been getting incorrect results when trying to create an NSDate object from a user specified date/time string and I've put together the following code below to illustrate the problem.
// Create two strings containing the current date and time
NSDateFormatter * dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd"];
NSDateFormatter * timeFormat = [[NSDateFormatter alloc] init];
[timeFormat setDateFormat:#"HH:mm:ss a"];
timeFormat.AMSymbol = #"AM";
timeFormat.PMSymbol = #"PM";
timeFormat.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"EDT"];
NSDate * now = [[NSDate alloc] init];
NSString *theDate = [dateFormat stringFromDate:now];
NSString *theTime = [timeFormat stringFromDate:now];
NSLog(#"The current date/time is (GTM): %#", now);
NSLog(#"The current date/time is (EDT): %# %#", theDate, theTime);
// Combine the date and time strings
NSMutableString * theDateTime = [[NSMutableString alloc] init];
theDateTime = [theDateTime stringByAppendingString:theDate];
theDateTime = [theDateTime stringByAppendingString:#" "];
theDateTime = [theDateTime stringByAppendingString:theTime];
// Define the formatter to parse the combined date and time string
NSDateFormatter * dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss a"];
dateFormatter.AMSymbol = #"AM";
dateFormatter.PMSymbol = #"PM";
dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"EDT"];
// Create an NSDate object using the combined date and time string
NSDate * theDateTimeObject=[dateFormatter dateFromString:theDateTime];
NSString * theDateTimeString=[dateFormatter stringFromDate:theDateTimeObject];
// Print the results
NSLog(#"theDateTimeObject (GMT) = %#", theDateTimeObject);
NSLog(#"theDateTimeString (EDT) = %#", theDateTimeString);
This code produces the following output:
The current date/time is (GMT): 2015-09-29 22:28:10 +0000
The current date/time is (EDT): 2015-09-29 18:28:10 PM
theDateTimeObject (GMT) = 2015-09-29 16:28:10 +0000
theDateTimeString (EDT) = 2015-09-29 12:28:10 PM
Clearly something is going wrong when the combined date and time string gets parsed by the date formatter to create the NSDate object. It seems to not understand the input time zone and returns a time in GMT that is several hours off what it should be (i.e. +4 hours). I've set the time zone to be "EDT", so not sure what else I can do to fix this problem, other than hard code an offset in the input, which I'd rather not do. Any help would be appreciated.

You are doing bad things by using both 24-hour format (HH) instead of 12-hour format (hh) and using AM/PM (a).
Change both instances of HH in your formats to hh and you should get the expected results.
You should also set the formatter's locale to the special locale en_US_POSIX to avoid issues with the device's 24-hour time setting.
Side note: Your use of NSMutableString is all wrong. Try this:
NSMutableString * theDateTime = [[NSMutableString alloc] init];
[theDateTime appendString:theDate];
[theDateTime appendString:#" "];
[theDateTime appendString:theTime];
or simply use:
NSString *theDateTime = [NSString stringWithFormat:#"%# %#", theDate, theTime];

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);

Need assistance regarding converting string to date [duplicate]

This question already has answers here:
Getting date from [NSDate date] off by a few hours
(3 answers)
Closed 8 years ago.
- (void) dateConverter{
NSString *string = [NSString stringWithFormat:#"%# %#", [[self dates]objectAtIndex:0], [times objectAtIndex:0]]; // string = 01-10-2014 11:36 AM;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy hh:mm a"];
[dateFormatter setLocale:[NSLocale currentLocale]];
NSDate *date = [[NSDate alloc] init];
date = [dateFormatter dateFromString:string];
NSLog(#"dateFromString = %#", date); // 2014-10-01 18:36:00 +0000
NSTimeInterval timeInterval = [date timeIntervalSince1970];
NSLog(#"dateFromString = %f", timeInterval); // 1412188560.000000
}
I am converting the string to actual date object, but I am getting different behavior
string = 01-10-2014 11:36 AM
is actual value I am trying to convert but getting this
2014-10-01 18:36:00 +0000
what is wrong with it?
The problem is a display issue.
You are using the default date formatter to print the date (NSLog used the description method).
The time is displayed in UTC (GMT) and it looks like you are in timezone -0700. The time is being displayed in timezone offset 0000.
The date/time in the system is based on the GMT time, that way times can be compared across timezones and everywhere on Earth the time is the same in the system at the same time.
Use a date formatter to get the date/time in the format you want.
Example code:
NSString *dateString = #"01-10-2014 11:36 AM";
NSLog(#"dateString = %#", dateString);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy hh:mm a"];
[dateFormatter setLocale:[NSLocale currentLocale]];
NSDate *date = [[NSDate alloc] init];
date = [dateFormatter dateFromString:dateString];
NSLog(#"dateFromString = %#", date);
NSString *displayDate = [dateFormatter stringFromDate:date];
NSLog(#"displayDate = %#", displayDate);
Output:
dateString = 01-10-2014 11:36 AM
dateFromString = 2014-10-01 15:36:00 +0000
displayDate = 01-10-2014 11:36 AM
Note: You can supply your own date format to get exactly the format what you want.

Need assistance regarding NSTimeInterval and timezone [duplicate]

This question already has an answer here:
NSDateFormatter and Time Zone issue?
(1 answer)
Closed 8 years ago.
-(NSTimeInterval)convertStringToDate:(NSString *) date {
NSString *dateString = date;
NSLog(#"dateString = %#", dateString);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy hh:mm a"];
[dateFormatter setLocale:[NSLocale currentLocale]];
NSDate *date1 = [[NSDate alloc] init];
date1 = [dateFormatter dateFromString:dateString];
NSLog(#"dateFromString = %#", date1);
NSString *displayDate = [dateFormatter stringFromDate:date1];
NSLog(#"displayDate = %#", displayDate);
return [date1 timeIntervalSince1970];
}
Why I am getting NSTimeInterval with wrong timezone?
You need to read up on the internal representation of NSDates. An NSDate is saved as the number seconds since midnight on 1 Jan, 1984 GMT (The Mac OS X "epoch date") . It represents an instant in time anywhere on the earth, but using a date in GMT as it's "zero date". To display it, you need to convert it to your local time zone.
NSDate has a couple of methods to convert a date to a number: timeIntervalSince1970, which converts an NSDate to the internet standard, which is the number of seconds since Midnight 1 Jan 1970 (The UNIX "epoch date"), and timeIntervalSinceReferenceDate, which converts to the number seconds since the Mac Epoch date.
If you display a date in NSLog:
NSLog(#"Date = %#", someNSDate);
It will be displayed in GMT.
Honestly, it's unclear what you're asking and my best guess is that you just don't understand the classes at play. I've annotated your code in the hope of aiding your comprehension.
Key point: NSDate does not have a time zone. It's an opaque time stamp.
-(NSTimeInterval)convertStringToDate:(NSString *) date {
// log the input string
NSString *dateString = date;
NSLog(#"dateString = %#", dateString);
// create an object that can apply a locale and a time zone in order to
// convert an NSDate to an NSString and vice versa
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy hh:mm a"];
[dateFormatter setLocale:[NSLocale currentLocale]];
// get a date that represents exactly now, for no reason as it's about
// to be thrown away
NSDate *date1 = [[NSDate alloc] init];
// convert to the NSDate that represents the given string.
date1 = [dateFormatter dateFromString:dateString];
// log the converted date. BECAUSE NSDATE DOES NOT HAVE A TIME ZONE,
// it will arbitrarily be displayed in UTC. Because it has to be
// displayed in something
NSLog(#"dateFromString = %#", date1);
// convert date1 back into a printable date; this will again apply
// a time zone and locale
NSString *displayDate = [dateFormatter stringFromDate:date1];
NSLog(#"displayDate = %#", displayDate);
// query the date for "The interval between the date object and
// January 1, 1970 at 12:00 a.m. GMT."; return that
return [date1 timeIntervalSince1970];
}

Setting up AM/PM for my time in iOS

My original date format is : 2014-03-14T10:35:24.537
So I first separate the time and date with componentsSeparatedByString, then I save the second half (the time part) to NSString time, while eliminating the microseconds. to the format 10:35. I'm trying to get it to add PM/AM but setDateFormat:#"hh:mm a" is not doing it. What am I doing wrong?
NSArray *components = [datestr componentsSeparatedByString:#"T"];
NSString *time = components[1];
time = [time substringWithRange:NSMakeRange(0, 5)];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm a"];
NSDate *timeFromString = [formatter dateFromString:time];
NSLog(#"%#", timeFromString);
When I log timeFromString, I get a null.
EDIT: I changed the formatter above to [formatter setDateFormat:#"hh:mm"]; and now the timeFromString logs as: 2000-01-01 18:35:00 +0000 when data coming in is 2014-03-14T10:35:28.42
A date formatter is used to convert dates to or from a string. A single date formatter cannot be used to convert between two different date formats. (At least, not without mutating the date formatter between operations.)
Use one formatter to convert the original string to a date. That formatter should not include AM/PM, since your original string doesn't.
Use a second formatter to convert the date to a new string. That formatter should include AM/PM, if you desire one.
Here 's how you should parse and convert the date:
//the date string
NSString *datestr = #"2014-03-14T10:35:24.537";
//strip the date
NSArray *components = [datestr componentsSeparatedByString:#"T"];
NSString *time = components[1];
time = [time substringWithRange:NSMakeRange(0, 5)];
//parse string to a date
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm"];
NSDate *timeFromString = [formatter dateFromString:time];
//Desired format
NSDateFormatter *timeformat = [[NSDateFormatter alloc] init];
[timeformat setDateFormat:#"hh:mm aa"];
NSString *finalString = [timeformat stringFromDate:timeFromString];
NSLog(#"final = %#",finalString);
OUTPUT:
final = 10:35 AM

loosing 1 hour after formatting a date string

i am formatting a date string with the following code:
and this is the format of the date string : 2013-10-08T20:30:00+03:00
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
[dateFormatter setDateFormat:#"EEEE"];
NSDateFormatter *formmatter = [[NSDateFormatter alloc] init];
formmatter.dateFormat = #"yyyy-MM-dd'T'HH:mm:SSSZZZ";
NSString *dataString = [meetingData objectForKey:#"start"];
if (![dataString isKindOfClass:[NSNull class]]) {
NSMutableString *mutableDate = [dataString mutableCopy];
[mutableDate deleteCharactersInRange:NSMakeRange(mutableDate.length - 3, 1)];
NSDate *gmtDate = [formmatter dateFromString:mutableDate];
NSDateFormatter *HHMM_Fromatter = [[NSDateFormatter alloc] init];
[HHMM_Fromatter setDateFormat:#"HH:mm"];
self.meetingTime = checkTheObject([HHMM_Fromatter stringFromDate:gmtDate]);
self.meetingDay = checkTheObject([dateFormatter stringFromDate:gmtDate]);
}
the output is forself.meetingTime : 19:30
and self.meetingDay is fine, why am i loosing 1 hour?
Your two date formatters HHMM_Fromatter and dateFormatter use different locales and thus, different time zones. You should explicitly set the timezone of both formatters to the same zone (probably [NSTimeZone localTimeZone]).
Note that the remaining parts of your date code seems fragile. You shouldn't do string calculations to remove the time zone from a string representation.
NSDate represents an absolute point in time and is not affected by time zones or locales. You should parse the string to one single NSDate and then use this date to calculate user facing string representations that take time zones into account.

Resources