Swift logo NSDateFormatter .com

Easy Skeezy Date Formatting for Swift and Objective-C

Date Input:
(enter in ISO8601 format)
Format text
Locale
Result
Friday, Dec 8, 2023
Friday, Dec 8, 2023
EEEE, MMM d, yyyy
12/08/2023
MM/dd/yyyy
12-08-2023 15:32
MM-dd-yyyy HH:mm
Dec 8, 3:32 PM
MMM d, h:mm a
December 2023
MMMM yyyy
Dec 8, 2023
MMM d, yyyy
Fri, 8 Dec 2023 15:32:43 +0000
E, d MMM yyyy HH:mm:ss Z
2023-12-08T15:32:43+0000
yyyy-MM-dd'T'HH:mm:ssZ
08.12.23
dd.MM.yy
15:32:43.184
HH:mm:ss.SSS

The following table’s sample column are mostly based on the time December 14th, 2008 4:35 PM UTC.

Characters Example
Year
y 2008
yy 08
yyyy 2008
Quarter
Q 4
QQQ Q4
QQQQ 4th quarter
Month
M 12
MM 12
MMM Dec
MMMM December
MMMMM D
Day
d 14
dd 14
F 2
E Tue
EEEE Tuesday
EEEEE T
EEEEEE Tu
Hour
h 4
hh 04
H 16
HH 16
a PM
Minute
m 35
mm 35
Second
s 8
ss 08
SSS 123
Time Zone
zzz CST
zzzz Central Standard Time
ZZZZ CST-06:00
Z -0600
ZZZZZ -06:00
For the full reference of available format options, see Unicode Technical Reference #35.

The main fallacy to be aware of: dateFormat is not locale-aware

You should be aware that using a custom dateFormat comes with a risk of falling into some fallacies.

Especially, you need to realize that the user can use different Locales, and that date formats are different for different locales, regions and user settings. For example one date formatted with a dateFormat that fits the US might become confusing for anyone in Europe.

The TL;DR

  • Use dateStyle and timeStyle over dateFormat whenever you can. Explain the date fallacies to your designer if you need to.
  • If you can't find a fitting dateStyle/timeStyle to format your UI dates, then at least use dateFormatter.setLocalizedDateFormatFromTemplate(…) to account for the user's locale.
  • When parsing ISO8601 internet dates, always use ISO8601DateFormatter
  • If you can't because your API format doesn't fit ISO8601 and you still absolutely need to use a custom dateFormat, then be sure to also set your dateFormatter.locale to the special value Locale(identifier: "en_US_POSIX").

Formatting user-visible dates for your UI

Apple already has a dedicated paragraph in their documentation about best practices for formatting a date to present to the user in a locale-aware way. Below is just the TL;DR.

Using dateStyle and timeStyle

The main recommendation to follow is to prefer using dateStyle and timeStyle over dateFormat.

This is because those are locale-aware and account for a lot of edge cases that you can otherwise miss when using a custom and hardcoded dateFormat.

I would even advise you to convince your designer against using a custom format and explain them that Date and Time is a tricky subject with lots of edge cases and that it's generally not worth using a custom format that might fit their assumptions about the locale and region they're used to use but might not fit a lot of other's.

Using DateFormatter's templating methods to auto-adjust for the user's Locale

If you still need to use a custom dateFormat, be sure that you use dateFormatter.setLocalizedDateFormatFromTemplate(…) or dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate:…options:…locale:…) instead of setting it to a hard-coded String.

Working with ISO8601 dates and fixed formats for APIs

Apple Documentation also has a dedicated section about those cases here.

Using ISO8601DateFormatter

If you need to parse ISO8601 dates, consider using ISODateFormatter instead of a DateFormatter with a custom dateFormat.

This class is dedicated to handle the ISO8601 standard and all its possible variants and edge cases better than using a custom dateFormat would.

Tip: One of the little-known options of ISO8601DateFormatter is that it is also able to handle fractional seconds if you set it up using formatter.formatOptions.insert(.withFractionalSeconds).

Always use the en_US_POSIX locale for fixed formats

In last resort, if you need to parse a date for an API that doesn’t fall into ISO8601 format, but that also isn’t intended for UI (and should thus not depend on the user’s locale/region/language), then that is the only case when you can use a fixed string as a value for dateFormatter.dateFormat.

BUT then ALWAYS also set your dateFormatter.locale to Locale(identifier: "en_US_POSIX") on your DateFormatter.

en_US_POSIX is a special locale that guarantees that the formatting and parsing won’t depend on the phone’s locale, and is designed exactly for parsing those “internet dates with fixed format”.

If you don't force the locale to en_US_POSIX, there are risks that your code might seem to work in some regions (like the US), but will fail to parse your API responses if the user has its phone set in another region (e.g. en_GB, es_ES or fr_FR), where date formatting is different, or use 12-hour time and not 24-hour time.

You can test this kind of edge case on device by setting your phone settings to use es_ES for example and set it to use 12-hour with am/pm, and try to parse a date like 2020-01-15T22:00:00Z.

For more information about those commonly overlooked cases, you can read Apple's TN1480.

This section was contributed by Olivier Halligon

nsdateformatter.com is written with Swift 5.5, originally as a means to learn open-source Swift, the Swift Package Manager, and deploying to Linux. It uses the Vapor web application framework and is deployed to Heroku.

The site is open source, so if you want to fix a bug or submit an enhancement, feel free to submit a pull request.

About the Author

Ben Scheirman

Ben Scheirman

twitter @subdigital

Ben is an experienced software developer from Houston, TX. He is the founder of NSScreencast, where you can find over 500 screencasts on iOS development topics.

You can find Ben on Twitter or his blog.

Want to see how to use DateFormatter in Swift?

Check out this free screencast:

Parsing and Formatting Dates