NSDateFormatter with 24 hour times - objective-c

I have a countdown timer which countsdown from the current date/time to a specific future date/time. It is working great except for one problem. I input the future date using NSDateFormatter and dateFromString. It doesn't seem to be able to accept any time (hour) over 12 though indicating it is not support 24 hour clock. Is there a way to enable 24 hour clock support or a workaround? Here is some of my code:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
NSDate *myDate = [df dateFromString:#"2010-03-14 15:00:00"];

NSDateFormatter follows the Unicode standard for date and time patterns. Use 'H' for the hour on a 24-hour clock:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *myDate = [df dateFromString:#"2010-03-14 15:00:00"];

I had the same problem and using HH worked only on some devices, like Roger also verified. In the end this was the solution that worked for me, I hope it works for others. Finding this answer was difficult, there are no forums with it, it was literally trial and error following the apple documentation.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormatter setLocale:enUSPOSIXLocale];
NSString *dateFormat = #"dd/MM/yyyy HH:mm"; //MM for month, mm for minutes
[dateFormatter setDateFormat:dateFormat];
[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
date = [dateFormatter dateFromString:string];

My solution on Swift:
let formatter = NSDateFormatter()
var defIdentifer = formatter.locale.localeIdentifier
if !defIdentifer.hasSuffix("_POSIX") {
defIdentifer = defIdentifer+"_POSIX"
let locale = NSLocale(localeIdentifier: defIdentifer)
formatter.locale = locale
}
formatter.dateFormat = "HH:mm"

I had a similar problem recently, instead of HH, NSDateFormatter ignored hh, a(AM/PM Symbol) and G (cyclic era name) in my app.
And I was surprised to find that if I go to localization setting of my device and make some random choice, all the freaks are gone and the error cannot be produced again. Very weird.
Then I tested on simulator to do some study on it. There is my solution:
After you created the NSDateFormatter, explicitly set the locale property even you are using current locale, more importantly, DON'T use [NSLocale currentLocale], this one is bugged and can be somehow "overriden" by user setting, use systemLocale or explicitly create an NSLocale instance using a locale identifer.

Taken from the Apple Technical Q&A on NSDateFormatters
Q: I'm using NSDateFormatter to parse an Internet-style date, but this fails for some users in some regions. I've set a specific date format string; shouldn't that force NSDateFormatter to work independently of the user's region settings?
A: No. While setting a date format string will appear to work for most users, it's not the right solution to this problem. There are many places where format strings behave in unexpected ways.
This is how I have done mine in Swift:
private let dateFormatter: NSDateFormatter = {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
dateFormatter.timeZone = NSTimeZone.init(forSecondsFromGMT: 0)
return dateFormatter
}()

Objective C version of getting NSDate from 24-hour string when user has set 12 hour format on their iPhone without changing locale and setting timezone:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSString *localeId = dateFormatter.locale.localeIdentifier;
if (! [localeId hasSuffix:#"_POSIX"]) {
localeId = [localeId stringByAppendingString:#"_POSIX"];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:localeId];
}
dateFormatter.dateFormat = #"yyyy-MM-dd'T'HH.mm.ss";
NSDate *date = [dateFormatter dateFromString:dateText];

Related

iOS NSDateFormatter Timezone

I have some code that takes a string, turns it into a date, reformats it then spits it out as another string:
[formatter setDateFormat:#"YYYY'-'MM'-'DD','HH:mm:ss','ZZZ"];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"America/New_York"]];
NSDate *date = [formatter dateFromString:combinedString];
[formatter setDateStyle:NSDateFormatterLongStyle];
NSString *finishedString = [formatter stringFromDate:date];
Basically, it works fine except for the timezones. All of the input strings are in timezone -0400, and I want the reformatted string to be in that timezone also, but the reformatted string keeps being converted forward 4 hours, even after I added the setTimeZone: line. Basically, I don't want to change the time at all, I just want to reformat it, and I can't understand what I am doing wrong?
It depends on format specified on the source of your dates. Most of the times I deal with dates in Unix/POSIX format. Then I use the following two lines of code:
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
[formatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] autorelease]];
Anyway, I recommend you to check the following Q&A from Apple Developers site:
http://developer.apple.com/library/ios/#qa/qa1480/_index.html
In Swift:
// Formatter configuration
let formatter: NSDateFormatter = NSDateFormatter()
let posix: NSLocale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.locale = posix
formatter.dateFormat = "d.M.y"
formatter.timeZone = NSTimeZone(name: "UTC")!
// String to date
let dateString: String = "1.1.2013"
let defaultDate: NSDate = formatter.dateFromString(dateString)!
println("defaultDate: \(defaultDate)")
self.dateOfBirthUIDatePicker.date = defaultDate

nsformatter dateFromString is nil

Im working on iphone app using xcode,objective c and targeting ios 5 minimum.
All I am trying to do is convert a string to a date. I have read lots on this and it should be a simple straight forward task. I have seen many other questions like this in forum but what is working for people doesnt seem to be working for me.
Here is what I am doing
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSString *dobText = [dict valueForKey:#"DateOfBirth"];
NSDate *dobDate = [dateFormatter dateFromString:dobText];
the dobText is always in format #"1999-01-01" which matches the date format set in the date formatter but the result when using date from string is always nil.
can anyone explain this to me and let me know how to fix it?
Look at the user preferences on your device. The documentation says:
Note that although setting a format string (setDateFormat:) in
principle specifies an exact format, in practice it may nevertheless
also be overridden by a user’s preferences—see Data Formatting Guide
for more details.
are you sure the date is using a - and not a – in the data you get from the dict. As i can reproduce a nil result when i use a – (alt + -)
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSString *dobText = #"2009-02-12";
NSDate *dobDate = [dateFormatter dateFromString:dobText];
NSLog(#"%#", dobDate);
Try doing this, will likely fix your problem.
NSString *dobText = [[dict valueForKey:#"DateOfBirth"] stringByReplacingOccurrencesOfString:#"—" withString:#"-"];
I suspect like bigkm say, your dashes may be getting in the way.
I would suggest you try a dummy string in line first. e.g.
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSString *dobText = #"1999-01-01" // [dict valueForKey:#"DateOfBirth"];
NSDate *dobDate = [dateFormatter dateFromString:dobText];
Now does that work? It should. Now triangulate another way:
Remove the dashes completely from the dob text, so that it has the format 'yyyyMMdd'
Have the date formatter look for this same format
Does that work? It should. And that would prove that the separator characters in your format are the issue and need some further inspection (or cleansing as bigkm suggested).
Side node re threading: NSDateFormatter is fine if you use it on the thread on which it was created. If you don't, you'll know b/c the app will crash.
If your date format is correct, I can suggest to set NSLocale to your NSDateFormatter.
For me this code works on simulator:
NSString *format = [NSString stringWithFormat:#"EEE, dd MMM yyyy HH:mm:ss Z"];
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:format];
NSDate *date = [df dateFromString:pubDateSttring];
but on the device date is always NIL.
I've found workaround of setting NSLocale:
df.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];

NSDateFormatter stringFromDate returns nil when using 12-hour time format

The following code is working for 24-hour time format.
+ (NSString *)formatDate:(NSDate *)date useLongStyle:(BOOL)useLongStyle showDate:(BOOL)showDate showTime:(BOOL)showTime
{
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.dateStyle = (useLongStyle) ? NSDateFormatterLongStyle : NSDateFormatterShortStyle;
dateFormatter.dateStyle = (showDate) ? dateFormatter.dateStyle : NSDateFormatterNoStyle;
dateFormatter.timeStyle = (showTime) ? NSDateFormatterShortStyle : NSDateFormatterNoStyle;
return [dateFormatter stringFromDate:date];
}
But when there are 12-hour format in the phone settings, it returns nil. Until I explicitly set region to e.g. Australia.
Time in date is in 24-hour format. Current locale is ru_RU (but in the en_EN it's the same).
You can use this
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
[formatter setLocale:locale];
I had a similar issue and found two solutions. One is to set the locale manually(i chose en_GB for 24 hour format) and the other is to set the timezone. Both worked individually for me. If you are not planning on dealing with dates that need to change according to time zones i suggest you go for setting locale because when dealing with timezones, the source and destination timezones comes into play and you need not deal with all that unless absolutely necessary. So try setting the locale, else go for timezone. Somehow, it helped override the system settings.
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];

NSDate issue with locale

I'm working on an iPad app that speaks to a private PHP API that I built up to communicate to a database. This API has to transfer Three dates, a starting time, an end time and the current time.
I want to test if the current time is in-between the date range. So I took the times (like 16:50:00) and convert them into NSDates:
NSDateFormatter *former = [[NSDateformatter alloc] init];
[former setDateFormat:#"HH:mm:ss"];
[former setLocale:[NSLocale currentLocale]];
NSDate *fromDate = [former dateFromString:#"10:15:00"];
NSDate *nowDate = [former dateFromString:#"13:25:00"];
NSDate *toDate = [former dateFromString:#"16:30:00"];
When I'm now logging the dates by using NSLog(#"\n%#\n%#\n%#", fromDate, nowDate, toDate); I see that the locale is incorrect.
It seems as the NSDateFormatter just ignores the locale setting. I also logged the currentLocales identifier which is the right one ("de_DE" in my case"). The locale remains +0000.
How can I fix this issue? Thanks, with kind regards, Julian
Alright, I've removed the previous answer, try the following
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSTimeZone *zone = [NSTimeZone localTimeZone];
[formatter setTimeZone:zone];
[formatter setDateFormat:#"HH:mm:ss"];
NSDate *date = [formatter dateFromString:#"10:15:00"];
NSLog(#"Time %#",[formatter stringFromDate:date]);

Create NSDate timezone issue

I am loading in dates from my web service, I'm sending dates in the format (GMT times): 02/11/11 10:56:09
I am creating an NSDate form this using NSDateFormatter as such:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy HH:mm:ss"];
NSDate *journeyDate = [dateFormatter dateFromString:str];
[dateFormatter release];
This works great, after I'm comparing this to the current date to get relative time intervals.
The problem is when the phone is set up in a different timezone, when I load in the date from my api, and use the date formatter, what seems to be happening is the phone is assuming the date string is local time and it's converting it to GMT.
Example:
I load in a date with the time 10am from the api.
The phone is set to PDT.
The date formatter is creating an NSDate assuming that my date string with 10am, is actually relevant to the phone.
I end up with a date and time equal to 5pm, adding 10 hours.
I am trying to specify in my date formatter that the string is GMT, but I'm having trouble, I've tried the following, adding GMT to the format:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy HH:mm:ss GMT"];
NSDate *journeyDate = [dateFormatter dateFromString:str];
[dateFormatter release];
This is not working.
Can anyone give any advice ?
Solution
Just a recap, I got it working with a terrible work around by appending GMT to the original string, and formatting that:
NSString * cheat = [NSString stringWithFormat:#"%# GMT", str];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy HH:mm:ss zzzz"];
NSDate *journeyDate = [dateFormatter dateFromString:cheat];
[dateFormatter release];
return journeyDate;
This was a kind of unstable hack, because if the string changed to include a timezone, it wouldn't work anymore. For anyone who needs to do as myself, the following is just a quick example on how to create an NSTimeZone.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
NSDate *journeyDate = [dateFormatter dateFromString:str];
[dateFormatter release];
return journeyDate;
Thanks for the quick help.
I suspect you just want to use NSDateFormatter.setTimeZone to force it to use UTC. You don't want to change the format string because presumably the string doesn't include the letters "GMT" - instead, you want to change which time zone the string is interpreted in, which is what setTimeZone will do.
You should use the setTimeZone method: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html