The following code worked in my app previous to iOS 4.2.
NSString *sunday = #"2011-03-13 20:15 -04:00";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm Z"];
NSDate *myDate = [dateFormatter dateFromString:sunday];
NSLog(#"sunday: %# myDate: %# fromNow: %d", sunday, myDate, [myDate timeIntervalSinceNow]);
Outputs:
sunday: 2011-03-13 20:15 -04:00 myDate: (null) fromNow: 0
What am I doing wrong here? myDate is null. Is there something about dateFormmater that changed and I'm missing. I imagine it's something trivial at this point as I've been staring at this...
If I understand the problem correctly, Z specifier parses both "-0400" and "GMT-04:00", not "-04:00". UTS #35 seems to confirm it. In my tests, though, it even parsed "GMT-0400". So "-04:00" does look like the only time zone format NSDateFormatter refuses to understand.
May I cynically suggest Apple's bug reporter as the answer?
Try quoting your dashes, eg:
#"yyyy'-'MM'-'dd HH':'mm Z"
My best reading here: http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns seems to suggest that this is actually required, though I seem to recall having used that same date formatting pattern in the past on iOS w/o issue.
Related
Below is the string of time stamp which is returned by some server
dateFromServer = 2013-07-08 16:45:03Z
I am doing the following to convert it to an NSDate
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"yyyy'-'MM'-'dd' 'HH':'mm':'ss'Z'"];
NSTimeZone *destinationTimeZone = [NSTimeZone systemTimeZone];
[format setTimeZone:destinationTimeZone];
dateFromServer = [dateFromServer stringByReplacingOccurrencesOfString:#"T" withString:#" "];
NSDate *oldTime = [format dateFromString:dateFromServer];
and I am getting
oldTime is 2013-07-08 20:45:03 +0000
It looks like +4 is added to the original time stamp
Why does it do that, and how do I avoid this situation?
The NSDate object doesn't preserve the timezone. Instead, when printing the date (I assume through a NSLog(#"%#", oldTime);) it will use the current timezone. If your system is set to GMT (+0000) then it will print like that.
The date is still correct, and if you force it to print with the correct time zone it will be correct.
I personally do not know objective C but I do know the point of the problem. I'll try to guess along with the syntax.
When you receive 2013-07-08 16:45:03Z the Z means UTC, or GMT+/-0000.
You are parsing it as a local timezone, or GMT-0400.
You then reemit it as reconverted into UTC with a 4 hour overcompensation.
To fix this, change:
NSTimeZone *destinationTimeZone = [NSTimeZone systemTimeZone];
to
NSTimeZone *destinationTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
Honestly, I'm not sure if you need to do any wrapping for the 0 to act as an NSInteger but that's what you need.
You may have been intermittently missing this bug as a failure to determine time would have fallen back to the desired effect.
Out of curiosity, could someone comment as to whether my code is at least partially correct?
I get a unix timestamp from the database and I am trying to create a human readable date from it. I am using this way
long t1=[time longLongValue];
NSDate* date=[NSDate dateWithTimeIntervalSince1970:t1];
where time is the timestamp. When I print date I get
1956-02-18 19:04:01 +0000
instead of
2013-01-02 12:31:03 +0000
The timestamp was 1356765933449
It is a matter of integer overflow, as Boris correctly pointed out in his answer.
I don't know what your time object is, but instead of a signed long int use a NSTimeInterval.
On iOS NSTimeInterval is currently defined as
typedef double NSTimeInterval;
but you shouldn't care too much about that. Sticking with type synonyms will protect you in case Apple decides to change the underlying definition to something else.
That said you should change your code to something like
NSTimeInterval epoch = [time doubleValue];
NSDate * date = [NSDate dateWithTimeIntervalSince1970:epoch];
Concerning the code maintainability issue I described before, here you are explicitly using a doubleValue (you don't have many options), but the good thing is that if Apple changes the NSTimeInterval definition to something not compatible with a double assignment, the compiler will let you know.
Try this
- (NSString *) getDateFromUnixFormat:(NSString *)unixFormat
{
NSDate *date = [NSDate dateWithTimeIntervalSince1970:[unixFormat intValue]];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"MMM dd, yyyy-h:mm"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
//NSDate *date = [dateFormatter dateFromString:publicationDate];
NSString *dte=[dateFormatter stringFromDate:date];
[dateFormatter release];
return dte;
}
The Unix timestamp has only 32 Bits available.
Because they use a signed int, they count the seconds from 1.1.1970. A 32 Bit signed int can only hold values up to 2147483647, where as you want it to be 1356765933449. That causes an overflow, and that causes your date to be invalid.
This is also known as the Year 2038 Problem, because 2147483647 (max value) will be hit on 03:14:07 UTC on Tuesday, 19 January 2038.
Then format the date using nsdateformatter. Details guide.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html
I'm trying to obtain NSDate from the given string:
NSString* dateString = #"March 23 04:00 AM";
NSDateFormatter* firstDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[firstDateFormatter setDateFormat:#"MMММ dd h:mm a"];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
[firstDateFormatter setLocale:locale];
NSDate* date = [firstDateFormatter dateFromString:dateString];
NSLog(#"date:%#", date);
The date I am getting is null where I've made a mistake?
There is an issue with the date format you set. According to apple
The format string uses the format patterns from the Unicode Technical
Standard #35
In your case you need to use stand-alone version of month that is LLLL not MMMM.
If you change this line, your code will work just fine
[firstDateFormatter setDateFormat:#"LLLL dd hh:mm a"];
The standard explains the standalone version as follow:
The most important distinction to make between format and stand-alone
forms is a grammatical distinction, for languages that require it. For
example, many languages require that a month name without an
associated day number be in the basic nominative form, while a month
name with an associated day number should be in a different
grammatical form: genitive, partitive, etc. Another common type of
distinction between format and stand-alone involves capitalization;
however, this can be controlled separately and more precisely using
the element as described in Section 5.19
ContextTransform Elements.
Btw. Read this it contains a lot of info along with better ways of initializing the dateformatter.
Use hh for two-digit hours:
[firstDateFormatter setDateFormat:#"MMММ dd hh:mm a"];
I want to calculate time span for twitter and facebook.
For twitter:-Tue Jul 19 11:08:46 +0000 2011
for facebook:-2011-07-18T15:25:09+0000
I want to convert it in to like,1 hrs ago,60 min ago,2 mint ago etc.
And how to compare these time values for Time sorting.
Kindly Provide any sample code or Any class reference link,So that i can do that.
I am in the process of doing something similar.
I would first convert the time given by Twitter and Facebook into a NSDate using NSDateFormatter's setDateFormat function. Then you can compare by using NSDate's timeSinceNow function.
In the case of Twitter, it might look like this…
NSDateFormatter *dateFM = [[NSDateFormatter alloc] init];
[dateFM setDateFormat:#"EEE MMM dd HH:mm:ss ZZZZ yyyy"]; //set the format that matches Twitter's result…
[dateFM setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US"]];
[dateFM setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
NSDate *twitterDate = [dateFM dateFromString:CTADateString];
float secondsOfTwitterDateSinceNow = [twitterDate timeIntervalSinceNow];
The result (secondsOfTwitterDateSinceNow) is the number of seconds elapsed since now which you can divide however you want (/60 = minutes, ect…)
I use a NSDateFormatter which works fine in the simulator, but I get a nil when I run it in the iPhone. I hardcoded the date to be sure of the format, but it fails anyway.
NSString *strPubDate = #"Fri, 8 May 2009 08:08:35 GMT";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setDateFormat:#"EEE, d MMM yyyy HH:mm:ss Z"];
NSDate *myDate = [dateFormatter dateFromString:strPubDate];
I tried with different region settings, languages etc. on the iPhone. Any idea what is going wrong?
This code seems to work correctly against the "GMT" tag.
NSString *strPubDate = #"Fri, 8 May 2009 08:08:35 GMT";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEE, d MMM yyyy HH:mm:ss zzzz"];
NSDate *myDate = [dateFormatter dateFromString:strPubDate];
RFC822 Date and Time specs use a few "zone" tags and I found the correct symbol to parse the "GMT" tag Format String for the iPhone NSDateFormatter
z~zzz: (Specific GMT Timezone Abbreviation)
zzzz: (Specific GMT Timezone Name)
Z: +0000 (RFC 822 Timezone
Thanks for all your help!
If you need to use a specific date format you might want to parse it "by hand" rather than using NSDateFormatter. Its behaviour does change depending on the locale, etc. and there are some bugs particularly when you have a timezone in your string.
Having said that, one option in finding what the problem is might be to use the getObjectValue:forString:range:error: method instead of dateFromString:. This way you get an NSError object that (in theory) would tell you what the problem is.
BTW, you don't need the NSDateFormatterBehavior10_4 line. iPhone OS only supports the 10.4+ options, though you won't get any errors if you use the "old" style in the Simulator.
I had also this problem recently (iOS5).
I needed to set also the locale of the NSDateFormatter to work on the device.
Without this, [dateFormatServer dateFromString:dateServer] was returning null.
NSString *dateServer = #"Fri, 8 May 2009 08:08:35 GMT";
NSDateFormatter *dateFormatServer = [[NSDateFormatter alloc] init];
[dateFormatServer setDateFormat:#"EEE, d MMM yyyy HH:mm:ss zzzz"];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_GB"];
[dateFormatServer setLocale:locale];
[locale release];
NSDate * date = [dateFormatServer dateFromString:dateServer];
Nothing stands out, but to help debug this you could try feeding NSDateFormatter a date object and seeing if the resulting string has any minor differences from the one you're trying to parse.
When I've parsed a date string with "GMT" at the end, I've used the "zzz" format, not "Z".
I second Manuel Spuhler's advice of manually parsing - not my favorite option, but Objective-C's options for that are way too complicated (and lacking in error reporting - anything wrong just spits nil, without a hint on the error).
One thing that worked for me is to use C's strptime to decouple the date, then reconstruct it as a NSDate object. For example, the code below tkes a string received as something like "Monday, 28-Sep-09 18:13:50 UTC" and converts it to a NSDate object adapting the UTC time for the local time:
struct tm time;
strptime([currentStringValue UTF8String], "%A, %d-%b-%y %H:%M:%S %z", &time);
NSDate* myDate = [NSDate dateWithString:
[NSString stringWithFormat:#"%04d-%02d-%02d %02d:%02d:%02d +0000",
time.tm_year+1900, time.tm_mon+1, time.tm_mday,
time.tm_hour, time.tm_min, time.tm_sec]
];
(could handle other zones by adding other struct tm parameters instead of the +0000 fixed time zone, see time.h entry on wikipedia for details):
strptime rescued me aswell.
struct tm time;
if (strptime([modDateString UTF8String], "%A, %d %b %Y %H:%M:%S", &time)) {
NSString *rDate=[NSString stringWithFormat:#"%04d-%02d-%02d %02d:%02d:%02d +0000",
time.tm_year+1900, time.tm_mon+1, time.tm_mday,
time.tm_hour, time.tm_min, time.tm_sec];
This code works with HTTP dates like Thu, 15 Apr 2010 13:53:56 GMT and Fri, 8 May 2009 08:08:35 GMT which was the original question