NSDate and NSDate stringFromDate are inconsistent - objective-c

I am trying to convert a mysql datetime field to another timezone. The conversion seems correct when I print the date object, however when I print the date as a string the time is incorrect. Source code and output are below.
Source:
edited - print original interval in seconds and string, add timezones
interval = [NSNumber numberWithDouble: seconds];
NSLog(#"interval in ms: %#",interval);
self.dateStamp = [[NSDate alloc] initWithTimeIntervalSince1970:seconds/1000];
if(![currentZone.name isEqualToString: timezone]){ //need to convert
NSDateFormatter *fromTZ = [[NSDateFormatter alloc]init];
[fromTZ setTimeZone:currentZone];
[fromTZ setDateFormat:#"hh:mm yyyy-MM-dd"];
NSLog(#"original date: %#",[fromTZ stringFromDate:self.dateStamp]);
NSDateFormatter *toTZ = [[NSDateFormatter alloc]init];
[toTZ setTimeZone:spotZone];
[toTZ setDateFormat:#"hh:mm yyyy-MM-dd"];
NSString *tempdate = [fromTZ stringFromDate:self.dateStamp];
NSDate *toDate = [toTZ dateFromString:tempdate];
NSLog(#"Date: %#",toDate);
NSLog(#"Date String: %#", [toTZ stringFromDate:toDate]);
}
Output:
interval in ms: 1384193573000
original date: 01:12 2013-11-11 //date in current timezone: America/Phoenix
Date: 2013-11-11 08:12:00 +0000 //date in new timezone: America/New York
Date String: 01:12 2013-11-11

NSDate has no concept of time zone, it is simply an object representing the number of seconds since January 1, 2001 GMT and represented in UTC. No matter what you try and set it to, when you straight log an NSDate its going to give you the same result. The only way to circumvent this is to use the NSDateFormatter which you've already done. Everything you've posted is the expected behavior.

Your server sends the time 1384193573000 (in milliseconds) since 1.1.1970, but not with respect to GMT as it is usually done, but with respect to a different time zone, "America/Phoenix" in your example.
Therefore you have to add a correction first, which is the difference between "America/Phoenix" and GMT:
NSTimeInterval serverTime = 1384193573000/1000.;
NSTimeZone *fromZone = [NSTimeZone timeZoneWithName:#"America/Phoenix"];
NSTimeInterval diff = [fromZone secondsFromGMTForDate:[NSDate dateWithTimeIntervalSince1970:0]];
NSDate *dateStamp = [NSDate dateWithTimeIntervalSince1970:(serverTime - diff)];
This was the crucial step. dateStamp is now a "proper" NSDate object representing
the time sent from the server.
What remains is to display the date. That is done as in the above comments and the other
answer. For example:
NSTimeZone *toZone = [NSTimeZone timeZoneWithName:#"America/New_York"];
NSDateFormatter *toTZ = [[NSDateFormatter alloc]init];
[toTZ setTimeZone:toZone];
[toTZ setDateFormat:#"HH:mm yyyy-MM-dd"];
NSString *result = [toTZ stringFromDate:dateStamp];
// result = 20:12 2013-11-11

Related

NSDate is wrong when doing 'dateFromString'

Im here in the UK and when working with dates in iOS they are always out by one hour (one hour behind), what I need is the correct time from an NSDate. Ive done the following, but i get two different times:
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ss";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
NSLog(#"NSDate %#",today);
NSLog(#"Time %#", [dateFormatter stringFromDate:today]);
NSDate*stringDate = [dateFormatter dateFromString:[dateFormatter stringFromDate:today]];
NSLog(#"Time date %#",stringDate);
Here is what is logged:
NSDate 2015-07-01 16:07:22 +0000
Time 2015-07-01 17:07:22
Time date 2015-07-01 16:07:22 +0000
Why is this happening? Am i missing something obvious? Surely if the string date is correct, then doing dateFromString should yield the correct results?
The reason I need an NSDate is so I can get the correct amount of seconds using [myTime timeIntervalSince1970]
2015-07-01 17:07:22 //is the correct date
Im expecting an NSDate object that is correct to my date and time.
Update
The answers below helped me find where I was going wrong, so I changed my approach, I was able to get the current timestamp doing the following:
NSString *timeStamp = [dateFormatter stringFromDate:[NSDate date]];
NSDate *curdate = [dateFormatter dateFromString:timeStamp];
int unix_timestamp = [curdate timeIntervalSince1970];
NSDate* referenceDate = [NSDate dateWithTimeIntervalSince1970: 0];
NSTimeZone* timeZone = [NSTimeZone systemTimeZone];
int offset = (int)[timeZone secondsFromGMTForDate: referenceDate];
int currentTimestamp = unix_timestamp + offset;
NSLog(#"CUrrent time stamp %d",currentTimestamp);
NSDate is an absolute moment of time, it does not have a timezone. The date object you have is correct: it is exactly the moment that code was executed.
If you need string representation of that moment of time in a specific time zone, use stringFromDate: just like you did.
If you need to know number values of hour/minute in a specific time zone, use -[NSCalendar components:fromDate:].
[calendar setTimeZone:...];
NSDateComponents* components = [calendar components:(NSHourCalendarUnit|NSMinuteCalendarUnit) fromDate:date];
The date formatter defaults to the local timezone. If you want a different timezone specify it. NSLog of a date used the 'NSDatedescription` method that defaults to GMT (UTC).
Examining the code:
NSDate *today = [NSDate date];
// Creates today's data in GMT (UTC) All NSDates are referenced to GMT.
NSLog(#"NSDate %#",today); (moved up for explanation ordering)
// NSDate 2015-07-01 16:07:22 +0000
// Displays the date in GMT
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ss";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
// Creates a date for matter with the system timezone
NSLog(#"Time %#", [dateFormatter stringFromDate:today]);
// Time 2015-07-01 17:07:22
// Creates a string representation in the system timezone and displays it
NSDate*stringDate = [dateFormatter dateFromString:[dateFormatter stringFromDate:today]];
// Creates a date from the string taking into the system timezone
NSLog(#"Time date %#",stringDate);
// Time date 2015-07-01 16:07:22 +0000
// Displays the date in GMT.

Error with formatting time in objective-c

I am trying to format the date of a blog post pulled from an RSS feed to be displayed in a table cell. I set the string "dateString" equal to the date received from the XML parser and log the results. Then, I convert the date to a new format, log it to the console, and I receive "null." Which in return gives me a time interval of 0, and displays "seconds ago" in my cell. I think there could be an error in my date format, but I checked many sources.
NSString *dateString = nil;
dateString = [datearray objectAtIndex:indexPath.row];
NSLog(#"Date Posted: %#", dateString);//Log date posted
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE, dd MMM yyyy HH:mm:ss ZZZ"];
NSDate *date = [dateFormat dateFromString:dateString];
NSLog(#"New Date: %#", date);//Log date posted
NSTimeInterval timeInterval = [date timeIntervalSinceNow];
NSLog(#"Time interval %f", timeInterval);
NSString *newTime = [timeIntervalFormatter stringForTimeInterval:timeInterval];
NSLog(#"New Time %#", newTime);
cell.dateLabel.text = [NSString stringWithFormat:#"%#", newTime];
Console Log:
2014-06-13 15:43:41.555 Cazenovia High School[13489:60b] Date Posted: Thu, 22 Aug 2013 13:33:44 +0000
2014-06-13 15:43:41.556 Cazenovia High School[13489:60b] New Date: (null)
2014-06-13 15:43:41.557 Cazenovia High School[13489:60b] Time interval 0.000000
2014-06-13 15:43:41.558 Cazenovia High School[13489:60b] New Time seconds ago
Edits:
Added the following lines, but still no change...
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormat setLocale:locale];
that was quite clear after running the project, because it seems there is an extra new-line character at tail of the dateString.
technically, which string you are working with is "Thu, 22 Aug 2013 13:33:44 +0000\0x0a", that is why the parser cannot work with it using that formatter.
I've modified the formatter to EEE, dd MMM yyyy HH:mm:ss ZZZ\n and it works properly now, that is how my console looks:

Trouble converting NSString to a NSDate

I have looked at other examples and I am still not able to convert this string to a date. After i run this code I get the following output from the NSLogs:
Prediction Conversion: 2012-07-01 00:00:00 +0000
Timestamp Conversion: 2012-06-24 00:00:00 +0000
Prediction: 604800.000000
Which isn't the hard coded dates i used. Does anyone know why? Code is below:
NSString *timeStamp = #"20120620 19:23";//[[predictionData objectAtIndex:0 ] valueForKey:#"tmstmp"];
NSString *predictionTime = #"20120620 19:30";// [[predictionData objectAtIndex:0 ] valueForKey:#"prdtm"];
NSDateFormatter *ts = [[NSDateFormatter alloc] init];
[ts setDateFormat:#"yyyyMMdd HH:dd"];
NSDate *convertedTS = [ts dateFromString:timeStamp];
NSDateFormatter *pt = [[NSDateFormatter alloc] init];
[pt setDateFormat:#"yyyyMMdd HH:dd"];
NSDate *convertedPT = [pt dateFromString:predictionTime];
NSTimeInterval timeDifference = [convertedPT timeIntervalSinceDate:convertedTS];
NSLog(#"Prediction Conversion: %#", [convertedPT description]);
NSLog(#"Timestamp Conversion: %#", [convertedTS description]);
NSLog(#"Prediction: %f", timeDifference);
Thanks!
You are using dd for your minutes instead of mm. This:
[ts setDateFormat:#"yyyyMMdd HH:dd"];
Should be this:
[ts setDateFormat:#"yyyyMMdd HH:mm"];
You formatter string is incorrect.
HH:dd
should be
HH:mm
In addition, you need to take the timezone into consideration. Without +XXXX specified, UTC is used by default. To set the timezone:
[ts setTimeZone:[NSTimeZone /*timezone*/]];
where /*timezone*/ is specified by the NSTimeZone class. There are many different ways of using a timezone (and many different timezones), so choose the one that is best for you.
You need to set the locale, set it to en_us_POSIX.
ts.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_us_POSIX"];
also, it should be HH:mm, not dd

current Date and Time - NSDate

I need to display the current Date and Time.
I have used ;
NSDate *currentDateNTime = [NSDate date];
I want to have the current date and time (Should display the system time and not GMT time).
The output should be in a NSDate format and not NSString.
for example;
NSDate *currentDateNTime = [NSDate date];
// Do the processing....
NSDate *nowDateAndTime = .....; // Output should be a NSDate and not a NSString
Since all NSDate is GMT referred, you probably want this:
(don'f forget that the nowDate won't be the actual current system date-time, but it's "shifted", so if you will generate NSString using NSDateFormatter, you will see a wrong date)
NSDate* currentDate = [NSDate date];
NSTimeZone* currentTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSTimeZone* nowTimeZone = [NSTimeZone systemTimeZone];
NSInteger currentGMTOffset = [currentTimeZone secondsFromGMTForDate:currentDate];
NSInteger nowGMTOffset = [nowTimeZone secondsFromGMTForDate:currentDate];
NSTimeInterval interval = nowGMTOffset - currentGMTOffset;
NSDate* nowDate = [[NSDate alloc] initWithTimeInterval:interval sinceDate:currentDate];
Every moment in time is the same moment in time everywhere around the world —- it is just expressed as different clock times in different timezones. Therefore, you can't change the date to some other date that represents the time in your timezone; you must use an NSDateFormatter that you feed with the timezone you are in. The resulting string is the moment in time expressed in the clock time of your position.
Do all needed calculations in GMT, and just use a formatter for displaying.
Worth reading
Does [NSDate date] return the local date and time?
Some useful resources for anyone coming to this more recently:
Apple date and time programming guide do read it if you're doing anything serious with dates and times.
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DatesAndTimes/DatesAndTimes.html#//apple_ref/doc/uid/10000039i?language=objc
Useful category on NSDate with lots of utilities does allow a ~new~ date to be generated based on an existing date.
https://github.com/erica/NSDate-Extensions
There's also a swift version of the category
https://github.com/erica/SwiftDates
You need an NSDateFormatter and call stringFromDate this method to get a string of your date.
NSDateFormatter *dateformater = [[NSDateFormatter alloc] init];
[dateformater setDateFormat:#"yyyyMMdd,HH:mm"];
NSString *str = [dateformater stringFromDate: currentDateNTime];
use this method
-(NSDate *)convertDateToDate:(NSDate *) date
{
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
NSDate *nowDate = [[[NSDate alloc] init] autorelease];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[formatter setDateFormat:#"yyyy-MM-d H:m:s"];
NSString * strdate = [formatter stringFromDate:date];
nowDate = [formatter dateFromString:strdate];
return nowDate;
}
this may return you what you want.
i hope you this may help you.

NSDateFormatter return incorrect date from string

I have a method,
+ (NSDate *) convertToDateFrom:(NSString *) dateString
{
if (dateString == nil || [dateString isEqual:#""]) return nil; //return nil if dateString is empty
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"EEEE, dd MMMM yyyy HH:mm"];
NSDate *date = [df dateFromString:dateString];
return date;
}
When I pass,
#"Monday, 21 November 2011 17:01" //Passed string
It returns a wrong date,
2011-11-21 23:14:00 +0000 // Output
I am not sure whether I am using those flags correctly or NSDateFormatter isn't properly converting my string to date.
Am I doing something wrong?
Thanks
The +0000 at the end of the date indicates GMT. All dates are stored relative to GMT; when you convert a date to a string or vice versa using a date formatter, the offset to your time zone is included. You can use NSDateFormatter's -setTimeZone: method to set the time zone used.
In short, you're not doing anything wrong in your code. Use [df stringFromDate:date]; to see that the date is correct. (You can also use NSDate's -descriptionWithCalendarFormat:timeZone:locale:.)
try using
df stringFromDate:date
Following worked on mine,
NSLog(#"Date for locale %#: %#",
[[dateFormatter locale] localeIdentifier], [df stringFromDate:date]);
gave me output as :
Date for locale en_US: Wednesday, 26 June 2013 15:50
Try setting the time zone and locale.
[df setLocale:[NSLocale currentLocale]];
[df setTimeZone:[NSTimeZone systemTimeZone]];