NSDateFormatter: Date according to currentLocale, without Year - ios

This can't be too difficult..
I want to display a date without the year. For example: "Aug, 2nd" (USA) or "02.08." (GERMANY)
It must work for a bunch of other locales as well.
My only idea so far is to do a normal format with year, and then remove the year-portion from the generated string.

I think you need to take a look at:
+ (NSString *)dateFormatFromTemplate:(NSString *)template options:(NSUInteger)opts locale:(NSLocale *)locale
As per the docs:
Returns a localized date format string representing the given date format components arranged appropriately for the specified locale.
Return Value
A localized date format string representing the date format components given in template, arranged appropriately for the locale specified by locale.
The returned string may not contain exactly those components given in template, but may—for example—have locale-specific adjustments applied.
Discussion
Different locales have different conventions for the ordering of date components. You use this method to get an appropriate format string for a given set of components for a specified locale (typically you use the current locale—see currentLocale).
The following example shows the difference between the date formats for British and American English:
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_GB"];
NSString *dateFormat;
// NOTE!!! I removed the 'y' from the example
NSString *dateComponents = #"MMMMd"; //#"yMMMMd";
dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:usLocale];
NSLog(#"Date format for %#: %#",
[usLocale displayNameForKey:NSLocaleIdentifier value:[usLocale localeIdentifier]], dateFormat);
dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:gbLocale];
NSLog(#"Date format for %#: %#",
[gbLocale displayNameForKey:NSLocaleIdentifier value:[gbLocale localeIdentifier]], dateFormat);
// Output:
// Date format for English (United States): MMMM d, y
// Date format for English (United Kingdom): d MMMM y
Extra code (add this to the code above):
//
NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
formatter.locale = gbLocale;
formatter.dateFormat = dateFormat;
NSLog(#"date: %#", [formatter stringFromDate: [NSDate date]]);
See here:
NSDateFormatter Class Reference

The two examples you give are very different from each other. One uses the abbreviated month name while the other uses the 2-digit month number. One uses a day ordinal ("2nd") while the other simply uses the 2-digit day number.
If you can accept using the same general format for all locales then make use of NSDateFormatter dateFormatFromTemplate:options:locale:.
NSString *localFormat = [NSDateFormatter dateFormatFromTemplate:#"MMM dd" options:0 locale:[NSLocale currentLocale]];
The result of this call will give back a format string you can use with NSDateFormatter setDateFormat:. The order of the month and day will be appropriate for the locale as well as any additional punctuation that should be added.
But again, this won't solve your exact needs because of the completely different formats you appear to want for each locale.

Swift 3
let template = "EEEEdMMM"
let locale = NSLocale.current // the device current locale
let format = DateFormatter.dateFormat(fromTemplate: template, options: 0, locale: locale)
let formatter = DateFormatter()
formatter.dateFormat = format
let now = Date()
let whatYouWant = formatter.string(from: now) // Sunday, Mar 5
Play with template to match your needs.
Doc and examples here to help you determine the template you want.

All the above answers are using an older api released in iOS 4. A newer api that was introduced in iOS 8 is available.
In the apple documentation for DateFormatter it provides the below sample code for only showing the day and month in a date. You can just pass the Locale.current to the DateFormatter if you don't want to specify a specific locale (I haven't been able to find out if this is the default implementation so would advise that you always set locale before using setLocalizedDateFormatFromTemplate(_:) which is suggested in the docs).
let dateFormatter = DateFormatter()
let date = Date(timeIntervalSinceReferenceDate: 410220000)
// US English Locale (en_US)
dateFormatter.locale = Locale(identifier: "en_US")
dateFormatter.setLocalizedDateFormatFromTemplate("MMMMd") // set template after setting locale
print(dateFormatter.string(from: date)) // December 31
// British English Locale (en_GB)
dateFormatter.locale = Locale(identifier: "en_GB")
dateFormatter.setLocalizedDateFormatFromTemplate("MMMMd") // // set template after setting locale
print(dateFormatter.string(from: date)) // 31 December

Related

NSDateFormatter doesn't support long-form day periods ('b' or 'B')

NSDateFormatter doesn't seem able to use the 'B' or 'b' format specifiers. 'B' is a little like 'a' (am/pm), but it outputs things like "at night" or "in the morning".
For example, this code:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en-US"];
NSString *dateTemplate = [NSDateFormatter dateFormatFromTemplate:#"h:mmB"
options:0
locale:locale];
[dateFormatter setDateFormat:dateTemplate];
[dateFormatter setLocale:locale];
NSString* now = [dateFormatter stringFromDate:[NSDate date]];
NSLog(#"String:\t%#\ndateTemplate:\t%#",
now,
dateFormatter.dateFormat);
...prints this:
String: 10:23 PM // Should be "10:23 at night"
dateTemplate: h:mm a // Note that 'B' turned into 'a' (am/pm)
Skipping dateFormatFromTemplate and putting the format directly into the formatter has the same effect.
The docs say that iOS 7 and later use tr35-31. It's unclear whether that spec supports 'B'. The formatting table for version 31 mentions 'a', but does not mention 'B'. On the other hand, the spec for all of tr35 does indeed mention 'B'.
If you download the actual CLDR data for version 31, you can find dayPeriod entries for "in the evening" etc.
The data exists; is there another formatting string I can use to get longer "day period" strings?
You are correct that B is used for a "natural language" description of the day period. However, the problem you're experiencing is arising from using it in a date format template.
It would seem that the CLDR does not recognize that it should keep B in a date format string when you ask it to localize a template format. Thus, it's substituting a back in to the final format string.
Incidentally, if you run through +[NSLocale availableLocaleIdentifiers], you'll see that there isn't any locale that support B in a template string.
However, if you use B in a date format string directly, then it works as expected:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"h:mm B";
NSLog(#"%#", [dateFormatter stringFromDate:[NSDate date]]);
Outputs:
12:57 in the afternoon
I'm able to get it to work in a iOS playground in Xcode 9. Sorry, the code below is in Swift, but it does seem to be working for me.
let loc = Locale(identifier: "en-US")
let testDF = DateFormatter()
testDF.dateFormat = "MM-dd-yyyy HH:mm"
testDF.locale = loc
let df = DateFormatter()
df.dateFormat = "h:mm B"
df.locale = loc
df.string(from: testDF.date(from: "09-21-2018 17:22")!) // "5:22 in the afternoon"
df.string(from: testDF.date(from: "09-21-2018 19:22")!) // "7:22 in the evening"
df.string(from: testDF.date(from: "09-21-2018 22:22")!) // "10:22 at night"
df.dateFormat // "h:mm B"

Swift NSDate ISO 8601 format

I am working on date formats in Swift and am trying to convert a string date to NSDate and an NSSate to string date (ISO 8601 format).
This is my code
let stringDate = "2016-05-14T09:30:00.000Z" // ISO 8601 format
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" // ISO 8601
let date = dateFormatter.dateFromString(stringDate)
print("Date = \(date)") // Output is 2016-05-14 16:30:00 +0000
// Again converting it date to string using stringFromDate
print("\(dateFormatter.stringFromDate(date!))") // 2016-05-14T09:30:00.000Z
I am trying to understand why I am getting NSDate in GMT format (adding 7 hours to time 09:30 to 16:30)?
If I convert that NSDate date variable to string, then I am getting the original string date. What is happening here?
You can use NSISO8601DateFormatter or ISO8601DateFormatter for Swift 3.0+
Your format string was wrong. You indicate a literal Z instead of "Z as zulu time". Remove the single quotes:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
You should always specified the locale as en_US_POSIX when parsing Internet time. This is so commonly overlooked that Apple created the ISO8601DateFormatter class in OS X v10.12 (Sierra).
If you're targeting iOS 11.0+ / macOS v10.13+ (High Sierra), you can simply use ISO8601DateFormatter with the withInternetDateTime and withFractionalSeconds options, like so:
let stringDate = "2016-05-14T09:30:00.000Z" // ISO 8601 format
let iso8601DateFormatter = ISO8601DateFormatter()
iso8601DateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let date = iso8601DateFormatter.date(from: stringDate)
print("Date = \(date)") // Output is 2016-05-14 09:30:00 +0000
For working with DateFormatter on older systems, see Apple Tech Note QA1480:
if you're working with fixed-format dates, you should first set the
locale of the date formatter to something appropriate for your fixed
format. In most cases the best locale to choose is "en_US_POSIX", a
locale that's specifically designed to yield US English results
regardless of both user and system preferences. "en_US_POSIX" is also
invariant in time (if the US, at some point in the future, changes the
way it formats dates, "en_US" will change to reflect the new
behaviour, but "en_US_POSIX" will not), and between machines
("en_US_POSIX" works the same on iOS as it does on OS X, and as it it
does on other platforms).
Here is a snippet of Swift 5, based on the sample code provided:
let stringDate = "2016-05-14T09:30:00.000Z" // ISO 8601 format
let rfc3339DateFormatter = DateFormatter()
rfc3339DateFormatter.locale = Locale(identifier: "en_US_POSIX")
rfc3339DateFormatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSS'Z'"
rfc3339DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let date = rfc3339DateFormatter.date(from: stringDate)
print("Date = \(date)") // Output is 2016-05-14 09:30:00 +0000

How to insert an NSDate into a column in an Azure managed database?

If you have an Azure back-end, with a column that is a DateTime or DateTimeOffset, the example code is rather sparse about how you send a timestamp value as part of an insert.
You can pass along an NSDate in the dictionary of values to insert, and the library will translate it for you and insert is as a UTC/GMT timezone value. However, my client specifically wanted this value to be in the timezone of the device which generated the data, which means I need to insert the value as a string, since NSDate has no inherent knowledge of timezones.
So...any suggestions on how to write the NSDate-to-string method?
How about this:
I changed my Azure Sql column datatype to datetimeoffset (which internally stores values as UTC as well as the timezone offset).
On client side I then used a date format with five Z's:
let date = NSDate() // local date time: Jun 27, 2014, 9:32 AM
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" // Note 5 Z's...
let strNow = formatter.stringFromDate(date) // "2014-06-27T09:32:49+02:00"
I was then able to insert the date string "2014-06-27T09:32:49+02:00" to my Azure table in that format.
Querying my Azure table for that same inserted date I received back:
2014/06/27 09:32:49 +02:00
There are two "gotchas":
The format is very specific for Azure to recognize and parse it correctly.
The required format is non-standard: the 'Z' specifier produces a timezone offset such as -0700 or +0800 but Azure will reject it if there isn't a colon between the hours and minutes, ie, -07:00 or +08:00. In the ARC solution below the colon is inserted after the string is generated.
(weird - format is a little off?)
+(NSString*)azureDateTimeString:(NSDate *)date
{
static NSDateFormatter *df = nil;
if(df == nil)
{
df = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] ;
[df setLocale:enUSPOSIXLocale];
df.timeZone = [NSTimeZone localTimeZone];
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZ"];
}
NSString *dateString = [df stringFromDate:date];
// insert a colon in the third position from the right of the string...
NSString *newString = [NSString stringWithFormat:#"%#:%#", [dateString substringToIndex:[dateString length]-2], [dateString substringFromIndex:[dateString length]-2]];
return newString;
}
In my case I found I had to append "Z" as a literal suffix rather than a timezone type indicator as part of the format string:
(My Azure column is DateTime and I'm using Xcode Swift)
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
let strNow = formatter.stringFromDate(date)
= "2014-06-27T00:40:52Z"
Note that I not only included 'T' as a literal but also 'Z'.
I could then successfully insert that date string into my Azure table and then, as a test, I could read it back and reverse it like this:
var creationDate = "2014-06-27T00:40:52Z"; //read back from azure table
let dtCreation = formatter.dateFromString(creationDate)
= Jun 27, 2014, 12:40 AM"

How do I get an ISO 8601 date on iOS?

It's easy enough to get the ISO 8601 date string (for example, 2004-02-12T15:19:21+00:00) in PHP via date('c'), but how does one get it in Objective-C (iPhone)? Is there a similarly short way to do it?
Here's the long way I found to do it:
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
dateFormatter.dateFormat = #"yyyy-MM-dd'T'HH:mm:ssZ";
NSDate *now = [NSDate date];
NSString *formattedDateString = [dateFormatter stringFromDate:now];
NSLog(#"ISO-8601 date: %#", formattedDateString);
// Output: ISO-8601 date: 2013-04-27T13:27:50-0700
It seems an awful lot of rigmarole for something so central.
Use NSDateFormatter:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"];
[dateFormatter setLocale:enUSPOSIXLocale];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
[dateFormatter setCalendar:[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]];
NSDate *now = [NSDate date];
NSString *iso8601String = [dateFormatter stringFromDate:now];
And in Swift:
let dateFormatter = DateFormatter()
let enUSPosixLocale = Locale(identifier: "en_US_POSIX")
dateFormatter.locale = enUSPosixLocale
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.calendar = Calendar(identifier: .gregorian)
let iso8601String = dateFormatter.string(from: Date())
iOS 10 introduces a new NSISO8601DateFormatter class to handle just this. If you're using Swift 3, your code would be something like this:
let formatter = ISO8601DateFormatter()
let date = formatter.date(from: "2016-08-26T12:39:00Z")
let string = formatter.string(from: Date())
As a complement to maddy's answer, the time zone format should be "ZZZZZ" (5 times Z) for ISO 8601 instead of a single "Z" (which is for RFC 822 format).
At least on iOS 6.
(see http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns)
An often overlooked issue is that strings in ISO 8601 format might have milliseconds and might not.
In other words, both "2016-12-31T23:59:59.9999999" and "2016-12-01T00:00:00" are legit, but if you are using static-typed date formatter, one of them won't be parsed.
Starting from iOS 10 you should use ISO8601DateFormatter that handles all variations of ISO 8601 date strings. See example below:
let date = Date()
var string: String
let formatter = ISO8601DateFormatter()
string = formatter.string(from: date)
let GMT = TimeZone(abbreviation: "GMT")
let options: ISO8601DateFormatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone]
string = ISO8601DateFormatter.string(from: date, timeZone: GMT, formatOptions: options)
For iOS 9 and below use the following approach with multiple data formatters.
I haven't found an answer that covers both cases and abstracts away this subtle difference. Here is the solution that addresses it:
extension DateFormatter {
static let iso8601DateFormatter: DateFormatter = {
let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
let iso8601DateFormatter = DateFormatter()
iso8601DateFormatter.locale = enUSPOSIXLocale
iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
}()
static let iso8601WithoutMillisecondsDateFormatter: DateFormatter = {
let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
let iso8601DateFormatter = DateFormatter()
iso8601DateFormatter.locale = enUSPOSIXLocale
iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
}()
static func date(fromISO8601String string: String) -> Date? {
if let dateWithMilliseconds = iso8601DateFormatter.date(from: string) {
return dateWithMilliseconds
}
if let dateWithoutMilliseconds = iso8601WithoutMillisecondsDateFormatter.date(from: string) {
return dateWithoutMilliseconds
}
return nil
}
}
Usage:
let dateToString = "2016-12-31T23:59:59.9999999"
let dateTo = DateFormatter.date(fromISO8601String: dateToString)
// dateTo: 2016-12-31 23:59:59 +0000
let dateFromString = "2016-12-01T00:00:00"
let dateFrom = DateFormatter.date(fromISO8601String: dateFromString)
// dateFrom: 2016-12-01 00:00:00 +0000
I also recommend checking Apple article about date formatters.
So use Sam Soffee's category on NSDate found here. With that code added to your project, you can from then on use a single method on NSDate:
- (NSString *)sam_ISO8601String
Not only is it one line, its much faster than the NSDateFormatter approach, since its written in pure C.
Just use NSISO8601DateFormatter from Foundation framework.
let isoDateFormatter = ISO8601DateFormatter()
print("ISO8601 string: \(isoDateFormatter.string(from: Date()))")
// ISO8601 string: 2018-03-21T19:11:46Z
https://developer.apple.com/documentation/foundation/nsiso8601dateformatter?language=objc
Update
From iOS 10, you can just use NSISO8601DateFormatter from Foundation
Original answer
From IS8601, the problems are the representation and time zone
ISO 8601 = year-month-day time timezone
For date and time, there are basic (YYYYMMDD, hhmmss, ...) and extended format (YYYY-MM-DD, hh:mm:ss, ...)
Time zone can be Zulu, offset or GMT
Separator for date and time can be space, or T
There are week format for date, but it is rarely used
Timezone can be a lot of spaces after
Second is optional
Here are some valid strings
2016-04-08T10:25:30Z
2016-04-08 11:25:30+0100
2016-04-08 202530GMT+1000
20160408 08:25:30-02:00
2016-04-08 11:25:30 +0100
Solutions
Parse step by step, like soffes ISO8601
Convert to basic format, like onmyway133 ISO8601
NSDateFormatter
So here is the format that I'm using in onmyway133 ISO8601
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.dateFormat = "yyyyMMdd HHmmssZ"
About the Z identifier Date Field Symbol Table
Z: The ISO8601 basic format with hours, minutes and optional seconds fields. The format is equivalent to RFC 822 zone format (when optional seconds field is absent)
About locale Formatting Data Using the Locale Settings
Locales represent the formatting choices for a particular user, not the user’s preferred language. These are often the same but can be different. For example, a native English speaker who lives in Germany might select English as the language and Germany as the region
About en_US_POSIX Technical Q&A QA1480 NSDateFormatter and Internet Dates
On the other hand, if you're working with fixed-format dates, you should first set the locale of the date formatter to something appropriate for your fixed format. In most cases the best locale to choose is "en_US_POSIX", a locale that's specifically designed to yield US English results regardless of both user and system preferences. "en_US_POSIX" is also invariant in time (if the US, at some point in the future, changes the way it formats dates, "en_US" will change to reflect the new behaviour, but "en_US_POSIX" will not), and between machines ("en_US_POSIX" works the same on iOS as it does on OS X, and as it it does on other platforms).
Interesting related quetions
Converting an ISO 8601 timestamp into an NSDate: How does one deal with the UTC time offset?
Why NSDateFormatter can not parse date from ISO 8601 format
Milliseconds NSDateFormatter to parse ISO8601 with and without milliseconds
Based on this gist: https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift, the following method can be used to convert NSDate to ISO 8601 date string in the format of yyyy-MM-dd'T'HH:mm:ss.SSSZ
-(NSString *)getISO8601String
{
static NSDateFormatter *formatter = nil;
if (!formatter)
{
formatter = [[NSDateFormatter alloc] init];
[formatter setLocale: [NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation: #"UTC"];
[formatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS"];
}
NSString *iso8601String = [formatter stringFromDate: self];
return [iso8601String stringByAppendingString: #"Z"];
}
With iOS 15 you get ISO860 as follows:
let iso8601String = Date.now.ISO8601Format()
If you are here because of a search result of the opposite way, here's the easiest solution:
let date = ISO8601DateFormatter().date(from: dateString)
This is a little bit simpler and puts the date into UTC.
extension NSDate
{
func iso8601() -> String
{
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone(name: "UTC")
let iso8601String = dateFormatter.stringFromDate(NSDate())
return iso8601String
}
}
let date = NSDate().iso8601()
Using Swift 3.0 and iOS 9.0
extension Date {
private static let jsonDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "UTC")!
return formatter
}()
var IOS8601String: String {
get {
return Date.jsonDateFormatter.string(from: self)
}
}
init?(fromIOS8601 dateString: String) {
if let d = Date.jsonDateFormatter.date(from: dateString) {
self.init(timeInterval: 0, since:d)
} else {
return nil
}
}
}

How to get 12 hour format time string when system is set to use 24 hour format

I want to get a time string like "10:00 PM", and I use the NSDateFormatterShortStyle to achieve this.
However when the system is set to use 24-hour format, what I got is "22:00".
Besides, I want to get a localized time string. For example, in Chinese, I want to get "下午10:00" instead of "10:00 PM". So I have to use the [NSLocale currentLocale], and can't use the en_US_POSIX locale.
Please help me to get a localized 12-hour format time string.
I need not only the hour part, and also the am/pm part. Besides, am/pm part may locate before the hour/minute part or after the hour/minute part depending on locale. Just like the system display time.
When system is set to use 12-hour format, it's just simple. But when the system is using 24-hour format, I just can't get the localized 12-hour format time string.
Well this should work:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:[NSDateFormatter dateFormatFromTemplate:#"hh:mm a" options:0 locale:[NSLocale currentLocale]]];
NSString *theTime = [dateFormatter stringFromDate:[NSDate date]];
This should get you a date formatter that will give the date in 12 hour format. The lower case hh indicates hours 1-12 format. See the Unicode Technical Standard #35 section of Date Format Patterns for details on the format string.
Unfortunately iOS will rewrite the format string based on the user's 24-hour format preference setting. I can find no way around that setting using Cocoa's date formatting. Since the 24-hour format will drop the am/pm designation, parsing the resulting string to convert hours greater than 12 will result in ambiguous time strings. Therefore the only remaining options I can see is honoring the users 24-hour preference setting or using other localization code. You can write your own, or maybe find an open source replacement.
Swift 3.0
var dateFormatter = DateFormatter()
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "hh:mm a", options: 0, locale: NSLocale.current)
var theTime: String = dateFormatter.string(from: Date())
NSInteger originalHour = hour;
BOOL isPm = YES;
if (hour >= 12) {
if (hour > 12)
hour -= 12;
}
else {
isPm = NO;
}
if (hour == 0)
hour = 12;

Resources