Objective-C - How to Get Date Formatter to Add Colon in Time Zone Offset - objective-c

I'm trying to format a date to match the format expected on the server side.
Wanted: 1985-01-24T00:00:00-07:00
Got: 1985-01-24T00:00:00-0700
Using: yyyy-MM-dd'T'HH:mm:ssZZZ
Is there a date format trick I can use to get that colon in there?
Here is my code. _birthdate is the date supplied by the birthdate selector:
NSDate *birthdate = (NSDate *)resultObject;
[_birthdate setNewTitle:[IRDate mmddyyFromNSDate:birthdate]];
//Set server-ready birthdate format
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZ"];
serverFormattedBirthDate = [formatter stringFromDate:birthdate];
NSLog(#"Birthdate: %#", serverFormattedBirthDate);

According to the Date Format Specifiers documentation, it looks like you'll need 5 Z's. That will get you things like "-08:00".
Aha, I see what you're getting at. If you run the formatting on OS X 10.8, you'll get the string you're expecting. However, if you run the formatting on iOS 5.1, you'll get the extra "GMT" in the string.
I'm guessing that the underlying data has changed in recent versions of the CLDR. In that case, I'm not sure what the correct answer is.

Related

Formatting a date from a string

I have looked at a number of other solutions on here, but can't seem to get this to work for my case.
I am consuming an API, from which some parts will be saved to core data, however the date format in the API doesn't match that of which core data expects,
The date that I am getting is in the format:
Jun 28, 2013 5:51:28 PM
I need to be able to sort my entity by this date in order to display the latest items. I tried the following format, but I can't seem to get a result that works, any ideas on how I can achieve this?
NSDate *createdDate = [key objectForKey:#"createdDate"];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"mm/dd/yyyy hhmmss"];
NSDate *date = [dateFormat dateFromString:createdDate];
createdDate can't be an NSDate. If it was your code would crash rather than just not working. It must be an NSString.
NSString *createdDate = [key objectForKey:#"createdDate"];
Next, the date string you say you receive is Jun 28, 2013 5:51:28 PM which doesn't even slightly match the format you're trying to use of mm/dd/yyyy hhmmss. For a start the format has slashes and the date string doesn't. The format must match the string construction exactly. Read the date formatter format spec again and modify your format. I don't have it to hand but it will be something like MMM dd, yyyy H:mm:ss a (don't just use that format, check it first).

NSDateFormatter dateFromString returns incorrect date [duplicate]

This question already has answers here:
Get NSDate from NSDate adjusted with timezone
(2 answers)
Closed 9 years ago.
I am trying to use NSDateFormatter in my app which takes a date string and formats it to an NSDate so that I can do Date Comparisons, however I am finding when I use dateFromString and format it the date is losing one day.
NSString *dateString = #"02-06-2012";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSLog(#"My Date = %#", dateFromString);
[dateFormatter release];
This outputs to the console:
My Date = 2012-06-01 23:00:00 +0000
Try adding this lines to your code,
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT+0:00"]];
or
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
SWIFT update :
Code from quetion,
let dateString = "02-06-2012"
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
var dateFromString : NSDate = dateFormatter.dateFromString(dateString)!
println("My Date \(dateFromString)")
And Solution ,
dateFormatter.timeZone = NSTimeZone(name: "GMT")
OR
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00")
I don't believe that Dhruv's answer is correct. In fact, it's not clear there's any problem at all. You just seem to have an incorrect expectation of what should happen and/or interpretation of what's happening.
NSDate represents a moment in time. This moment does not have one unique name. It will be known by different names in different places and under different naming systems (time zones, calendars). NSDate doesn't deal with any of this, except lamely in its -description method, where it has to produce a string representation of that moment.
Second, a string like "02-06-2012" doesn't specify a precise moment in time. First of all, it's just a date with no time information, so NSDateFormatter just defaults to the first moment for that date. Second, it doesn't specify the time zone. The first moment of the calendar day is a different moment in each time zone. Unless you specify a time zone with -setTimeZone: or the string itself carries time zone information, NSDateFormatter assumes that any date strings you ask it to parse are in the current time zone.
So, your dateFromString object represents the first moment of the specified date, 02-06-2012, in your time zone. I expect this is what you wanted. However, you then got confused by the way that NSDate describes itself when logged. As I said, NSDate has to pick some "name" (string representation) for the moment it represents and which name it picks is fairly arbitrary. These days it is picking the name that the moment is known by in UTC. I gather from the log output shown in your question that you are located at UTC+0100. So, the date may look like it's one day earlier but it really is the same moment you specified. In other words, "2012-06-01 23:00:00 +0000" and "2012-06-02 00:00:00 +0100" are two equivalent names for exactly the same moment in time. You just aren't used to seeing the first one and misinterpreted it.
The lesson is that you have to stop relying on NSDate's self-description to be in any particular time zone. Really, you have to not rely on anything about it, since it's not documented. In fact, the docs for -[NSDate description] state, "The representation is not guaranteed to remain constant across different releases of the operating system."
Dhruv's solution seems to help merely because it causes NSDateFormatter and -[NSDate description] to agree on the time zone. But that's unreliable. It wouldn't work on Snow Leopard, for example, because -[NSDate description] used the local time zone instead of UTC in that version of the frameworks.
More importantly, though, it alters the actual moment represented by the NSDate object you get from NSDateFormatter's interpretation of your date string. I suspect you really want that to have a specific meaning – you want the string to be interpreted as being in the local time zone – and his solution thwarts your intent.
tl;dr: you were getting the date you wanted all along; don't rely on -[NSDate description]; don't use Dhruv's solution

NSDateFormatter dateFromString produces nil after first call in same method

Before Xcode 4 I used to use NSDate initFromString but it is now deprecated and produces errors in Xcode 4.2. So I jumped over to using NSDateFormatter dateFromString but ran into an issue in a method I call that gets a sunrise date from string and a sunset date from string to determine if it is day or night (so same method). The first call works fine, but the second call returns nil. I decided to see if it was repeatable so I created the following simple method and dumped it into another project in an innocuous place:
- (void)testDateFormatter
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat: #"yyyy-MM-dd hh:mm:ss Z"];
NSString *srDateTimeString = #"2011-11-09 07:08:00 -0800";
NSString *ssDateTimeString = #"2011-11-09 17:08:00 -0800";
NSDate *sunriseDateTime = [formatter dateFromString: srDateTimeString];
NSDate *sunsetDateTime = [formatter dateFromString: ssDateTimeString];
return;
}
The first call returns the correct date. The second call returns nil. I have tried several variations (such as creating two separate NSDateFormatters, preinitializing the dates, preinitializing the dates to the current time and then reassigning) but none do the expected thing.
Does anyone know what is going on here? Since I hadn't found any reference to this error anywhere I submitted it to Apple (bug #10420498).
Jack
In the second string, the hour is 17 (24-hour format) but the format string uses hh (lowercase) which is for 12-hour format.
Change the format string to yyyy-MM-dd HH:mm:ss Z.
In the documentation, see Date Formatters which contains a link to the Unicode Date Format Patterns listing each format specifier.

Problem converting Ruby on Rails DateTime to NSDate

Why is this ...
NSString *mydate = #"2011-07-20T23:59:00-07:00"
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss'Z'"];
NSLog(#"%#", [[dateFormatter dateFromString:mydate] description]);
... returning "(null)" in the console?
Your date format of #"yyyy-MM-dd'T'HH:mm:ss'Z'" means that it's looking for a literal "Z" character at the end of the string. However, your string is:
#"2011-07-20T23:59:00-07:00"
I don't see a "Z" there, do you? Thus, the date comes back as nil because your string does not match the format specified.
According to the Date Formatting Patterns documentation, you're probably looking for the format string of:
#"yyyy-MM-dd'T'HH:mm:ssZZ"
However, even that might not work, because if you notice your source string has a colon (":") in between the hours and minutes of the timezone offset. There's no timezone specifier that accounts for that. If that is indeed the format in which ROR is returning the date, then ROR is wrong.
I am doing transfer of Dates from Ruby to iOS via a JSON API and I believe I have read the same article.
http://www.cimgf.com/2012/05/29/importing-data-made-easy/
I am almost positive that they have mistakenly added the 'Z' as a string literal
-
To get Ruby to output as you are probably expecting I did the following:
1.9.3-p392 :012 > s = Time.now
=> 2013-05-03 15:47:51 +0100
1.9.3-p392 :013 > s.strftime("%Y-%m-%d\T%H:%M:%S%:z")
=> "2013-05-03T15:47:51+01:00"
Notice the %:z that is available in Ruby 1.9.3 at least
Is there a Ruby 1.8.7 time.strftime %z bug?

nil result from NSDateFormatter with 0's in format string

I'm getting a date from a webservice back in the form MM00yyyy -- it is just the two-digit month, followed by two 0's, and then the four-digit year. When I do this:
NSString *expDate = #"12001975";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"MM00yyyy"];
NSDate postDate = [dateFormat dateFromString:expDate];
[dateFormat dateFromString] returns nil for some reason. I have also tried MMddyyyy, and MM'0''0'yyyy, with no success either way. I am converting a similar date, except the 0's are actually the day with no problem using the same method.
To get this working, I would just use the following pattern MMHHyyyy. Since you need only the date and not neccessarily the hour, the HH will use the 00 to set the time as zeroth hour and hence you will get the date that you are looking for. Again this is just a hack and a workaround only to solve your current problem.
Have a look at the Date Formatting Guide from Apple. The section "Use Format Strings to Specify Custom Formats" lists all the different standards the are supported by various iOS versions for specifying a format string. I would say that "00" is not allowed, so that is the reason why "MM00yyyy" is failing. Similarly, "MMddyyyy" is also failing because no day can be "00".
I don't know if you can have more luck with UNIX functions, as the Apple doc suggests:
For date and times in a fixed, unlocalized format, that are always guaranteed to use the same calendar, it may sometimes be easier and more efficient to use the standard C library functions strptime_l and strftime_l.
Be aware that the C library also has the idea of a current locale. To guarantee a fixed date format, you should pass NULL as the loc parameter of these routines. This causes them to use the POSIX locale (also known as the C locale), which is equivalent to Cocoa's en_US_POSIX locale, as illustrated in this example.
struct tm sometime;
const char *formatString = "%Y-%m-%d %H:%M:%S %z";
(void) strptime_l("2005-07-01 12:00:00 -0700", formatString, &sometime, NULL);
NSLog(#"NSDate is %#", [NSDate dateWithTimeIntervalSince1970: mktime(&sometime)]);
// Output: NSDate is 2005-07-01 12:00:00 -0700
Getting the format strings right seems much more like art than science. I suggest you make a new string without the 00 in it and then have your DateFromatter process that with "MMyyyy".
While this might not be the "correct" way to do it, it should solve your problem pretty quickly.
The zeros are unsupported symbols. Apple supports the following characters for date formatting: http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns See the day section.