NSDateFormatter not converting to correct date - ios

I have a problem converting a string date to NSDate since the conversion is not correct. This is my code:
NSString *stringDate = #"6/20/2014 8:38:52 PM";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM/dd/yyyy hh:mm:ss a"];
NSDate *timeStamp = [dateFormatter dateFromString:stringDate];
The log always says TIMESTAMP: 2014-06-20 12:38:37 +0000.
How can I convert it to a correct date? Thanks in advance.

I believe you are doing this to display the date in the log:
NSLog(#"timeStamp = %#", timeStamp);
Instead keep the date formatter around (store it globally or something) and do:
NSLog(#"timeStamp = %#", [dateFormatter stringFromDate:timeStamp]);
The difference is the first line of code calls [NSDate description] to format the date, which uses UTC/GMT time zone, where as the second line of code uses the time zone configured in the date formatter (which by default is the same the locale's time zone), and crucially the same time zone you used to parse the string in the first place.

Add
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
And you get date in UTC time zone.

You can use this. It will give you proper output
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[dateComponents setYear:2014];
[dateComponents setMonth:6];
[dateComponents setDay:20];
[dateComponents setHour:8];
[dateComponents setMinute:38];
[dateComponents setSecond:52];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [calendar dateFromComponents:dateComponents];
//NSDate *timeStamp = [dateFormatter dateFromString:stringDate];
NSLog(#"date = %#",date);
//solutions[2247:70b] date = 2014-06-20 08:38:52 +0000 printing date

Related

Strange NSDate after changing hour

I want to change hour in NSDate. I did something like this:
NSDate *final = [gregorian dateBySettingUnit:NSCalendarUnitHour value:hour.intValue ofDate:self.dateForNewEvent options:NSCalendarMatchStrictly];
where self.dateForNewEvent = 2018-07-09 07:24:13 +0000
and hour.intValue = 5 and i expect date = 2018-07-09 05:00:00 + 0000 but i got 2018-07-10 03:00:00 UTC. How should I do it to get expected date ?
To change the hours of a specific NSDate, you need to manipulate it via NSDateComponents. Please try below code for the same:
NSDate *now = [NSDate date]; // YOUR DATE INSTANCE
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier: NSCalendarIdentifierGregorian];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond fromDate:now];
[components setHour:5];
NSDate *today5am = [calendar dateFromComponents:components];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
NSLog(#"Date ===>>> %#",[dateFormatter stringFromDate:[NSDate date]]);
Hope this helps!
I think you are mixing NSDate with NSCalendar: NSDate is a point in time, internally represented in UTC. To get the local date/time as it is displayed on a calendar or watch , you use NSCalendar.
So if you are in MEST (UTC+2) and set the time to "5" hours on your calendar, this will be UTC "3" hours.
To get the calendar date/time back, you could use components(_:from:) from NSCalendar.
Just check this code:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
NSDate * dateForNewEvent = [dateFormatter dateFromString: #"2018-07-09T07:24:13+00:00"];
NSLog(#"dateForNewEvent: %#", dateForNewEvent);
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *comps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:dateForNewEvent];
[comps setHour:5];
NSDate *final = [gregorian dateFromComponents:comps];
NSLog(#"final: %#", final);
Output as expected:
2018-07-09 11:11:43.542 jdoodle[22:22] dateForNewEvent: 2018-07-09 07:24:13 +0000
2018-07-09 11:11:43.542 jdoodle[22:22] final: 2018-07-09 05:24:00 +0000

setting time when formatting date using NSDateformatter

I have following code to convert string to date. Is it possible that it sets time as "00:00:00" and not the current time?
NSDateFormatter *dateformat = [[NSDateFormatter alloc] init];
[dateformat setDateFormat:#"yyyy-MM-dd"];
NSString *str = #"2014-08-08";
NSDate *dt = [dateformat dateFromString:str];
This gives dt as "2014-08-08 15:20:00 +0000" because I did the operation at 15:20.
Edit: I am using this date to convert it to integer later to store it in database:
int t = [dt timeIntervalSince1970];
If you are displaying the date dt with NSLog you will see what the date description method provides. If you want to see the date in a specific way that suits you use NSDateFormatter to format the date.
Example:
NSDateFormatter *dateformat = [[NSDateFormatter alloc] init];
[dateformat setDateFormat:#"yyyy-MM-dd"];
NSString *str = #"2014-08-08";
NSDate *dt = [dateformat dateFromString:str];
NSDateFormatter *displayDateformat = [[NSDateFormatter alloc] init];
[displayDateformat setDateFormat:#"yyyy-MM-dd"];
NSString *displayDateString = [displayDateformat stringFromDate:dt];
NSLog(#"displayDateString: %#", displayDateString);
Output:
2014-08-08
Note per Apple docs: "This method returns a time value relative to an absolute reference dateā€”the first instant of 1 January 2001, GMT."
A good practice is to use NSDateComponents
NSDate *yourDate = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:yourDate];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
// Set the time components manually
[dateComponents setHour:0];
[dateComponents setMinute:0];
[dateComponents setSecond:0];
yourDate = [calendar dateFromComponents:dateComponents];
Update
iOS8 :
[[NSCalendar currentCalendar] startOfDayForDate:[NSDate date]];

IOS date conversion + timezone issue + returning always -1 day even after timezone.

I wrote function to convert date from string to date. The code is as below
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateFormatter *df = [[NSDateFormatter alloc]init];
[df setTimeZone:[NSTimeZone localTimeZone]];
[df setDateFormat:#"dd MMM, yyyy"];
NSDateComponents *comp = [calendar components:NSMonthCalendarUnit|NSYearCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:[df dateFromString:nDate]];
[comp setTimeZone:[NSTimeZone localTimeZone]];
NSLog(#"%#",[calendar dateFromComponents:comp]);
I am passing nDate as: 10 Feb,2014, but function is retiring me 2014-02-09 18:30:00 +0000. Let me know what I am doing wrong. Thanks in advance.
The NSLog() will just call NSDate's description method. This will not set the timezone to what you expect when logging your date. You can try this instead:
NSLog(#"%#", [df stringFromDate:[calendar dateFromComponents:comp]]);

Conversion of NSString to NSDate conversion - incorrect result

In short words I plan to get current dateTime, change the time and make it local to Malaysia Time by applying +0800 to timezone.
The result is unexpected :
-(NSDate *)departureDateTime
{
NSDate *date = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *components = [gregorian components: NSUIntegerMax fromDate: date];
[components setHour: 7];
[components setMinute: 59];
[components setSecond: 17];
NSDate *newDate = [gregorian dateFromComponents: components];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-mm-dd HH:mm:ss Z"];
[dateFormat setLocale:[NSLocale currentLocale]];
NSString *newDateString = [NSString stringWithFormat:#"%#",newDate];
NSString *maskString = [NSString stringWithFormat:#"%#", [newDateString substringToIndex:20]];
NSString *append = [maskString stringByAppendingString:#"+0800"];
NSLog(#"%#",append);
NSDate *finalLocalDate = [dateFormat dateFromString:append];
return finalLocalDate;
}
Results :
for NSLog Append : 2013-12-07 23:59:17 +0800
but finalLocalDate : 2013-01-07 15:59:17 +0000
Found the answer with much shorter solution, so I posted here in case it helps anyone in future.
for returning, the problem was different time zones so by adding this line of
[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:(+0*3600) ] ];
we set the timezone to system time zone then we remove unnecessary codes :
-(NSDate *)departureDateTime
{
NSDate *date = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *components = [gregorian components: NSUIntegerMax fromDate: date];
[components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:(+0*3600) ] ];
[components setHour: 7];
[components setMinute: 59];
[components setSecond: 17];
NSDate *newDate = [gregorian dateFromComponents: components];
NSLog(#"%#",newDate);
return newDate;
}
Correct Result : 2013-12-08 07:59:17 +0000
try this:
NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
NSDate *malaysianTime = [NSDate dateWithTimeIntervalSince1970:now+(8*60*60)]; //8h in seconds
If your computer is running in the correct timezone don't set a timezone.
Create your newDate value and then --
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:#"yyyy-MM-dd HH:mm:ss Z"];
NSString* printableDate = [fmt stringFromDate:newDate];
NSLog(#"The date is %#", printableDate);
Only set a timezone (in both NSCalendar and NSDateFormatter) if the desired timezone is not the one your computer/phone is currently using.
Note that if you NSLog newDate directly it will print in GMT timezone. This is the way it's supposed to be -- you always use NSDateFormatter for a printable date. When you NSLog an NSDate directly you get GMT, by design.

Get the difference time between two NSString in Objective C

I have two strings coming from my server in which I store the time, and I need to compare the time interval between those two, in minutes, and if it's necessary, in hours. Should I convert to NSDate or use NSString?
The NSStrings look like:
NOW 14:22
LAST TIME 10:18
EDIT #1
Since everyone is saying me to use NSDate, i converted the data in my database to DATETIME, and now i can compare the two NSDate using the following code :
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"pt_BR"]];
[dateFormatter setDateFormat: #"yyyy-MM-dd HH:mm:ss"];
NSDate *currentDateTimeWithOffset = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSString *strDate = [dateFormatter stringFromDate:currentDateTimeWithOffset];
NSDate * now = [dateFormatter dateFromString:strDate];
NSDate *date = [dateFormatter dateFromString:#"2013-04-09 12:10:18"];
NSLog(#"Difference %f",[now timeIntervalSinceDate:date]);
And the result is the following :
Difference 864.000000
NOW 2013-04-09 15:24:42 +0000
LAST DATE 2013-04-09 12:10:18
Is that correct? the Difference is in Seconds?
If the format gets more complex than the one you've shown, consider using NSDateFormatter. For the simple example:
NSArray *hoursMins = [timeString componentsSeparatedByString:#":"];
NSInteger timeInMins = [hoursMins[0] intValue] * 60 + [hoursMins[1] intValue];
Then subtract the two times in minutes. The date formatter approach looks like this:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"HH:mm"];
NSDate *date = [df dateFromString:timeString];
You can get a difference in seconds between two dates using:
[date timerIntervalSinceDate:anotherDate];
NSDateFormatter is the "clean" way to do it. But if you are looking for quick and dirty, and those are the actual strings you are getting (that include the NOW and LAST TIME), I'd just use a specific NSRange to pull the hours and minutes out and compare them.
Make sure, though that you check the hours, and if the "now" hour is before the "last time" hour, you add 24 to the now to throw in the day rollover.
With only NSString, NSDateFormatter is used to get NSDate
NSDateFormatter *rfc3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[rfc3339DateFormatter setDateFormat:#"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
[rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
// Convert the RFC 3339 date time string to an NSDate.
NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
If you had separate values for hours, minutes and seconds you could use NSCalendar
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setYear:1965];
[comps setMonth:1];
[comps setDay:6];
[comps setHour:14];
[comps setMinute:10];
[comps setSecond:0];
NSDate *date = [gregorian dateFromComponents:comps];
[comps release];
And a perfect solution would be to use timestamps instead of NSString. Not only it's easy to convert timestamps to NSDate (NSDate +dateWithTimeIntervalSinceReferenceDate)and then to NSString when needed, but you can also get the time difference by subtraction.
And with two NSDate objects the time difference is calculated with NSDate -timeIntervalSinceDate.

Resources