{"id":45066,"date":"2024-09-23T15:09:04","date_gmt":"2024-09-23T19:09:04","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=45066"},"modified":"2025-12-23T11:15:06","modified_gmt":"2025-12-23T16:15:06","slug":"iso8601dateformatter-and-fractional-seconds","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2024\/09\/23\/iso8601dateformatter-and-fractional-seconds\/","title":{"rendered":"ISO8601DateFormatter and Fractional Seconds"},"content":{"rendered":"<p><a href=\"https:\/\/augmentedcode.io\/2024\/09\/23\/how-to-keep-dates-microseconds-precision-in-swift\/\">Toomas Vahter<\/a>:<\/p>\n<blockquote cite=\"https:\/\/augmentedcode.io\/2024\/09\/23\/how-to-keep-dates-microseconds-precision-in-swift\/\">\n<p><code>DateFormatter<\/code> is used for converting string representation of date and time to a <code>Date<\/code> type and visa-versa. Something to be aware of is that the conversion loses microseconds precision. This is extremely important if we use these <code>Date<\/code> values for sorting and therefore ending up with incorrect order. Let&rsquo;s consider an iOS app which uses API for fetching a list of items and each of the item contains a timestamp used for sorting the list. Often, these timestamps have the ISO8601 format like <code>2024-09-21T10:32:32.113123Z<\/code>. Foundation framework has a dedicated formatter for parsing these strings: <a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/iso8601dateformatter\">ISO8601DateFormatter<\/a>.<\/p>\n<p>[&#8230;]<\/p>\n<p>Fortunately this can be fixed by manually parsing microseconds and adding the missing precision to the converted <code>Date<\/code> value.<\/p>\n<\/blockquote>\n<p><code>.withFractionalSeconds<\/code> only preserves three digits. Cocoa trivia: <code>NSISO8601DateFormatter<\/code> is an <code>NSFormatter<\/code>, not an <code>NSDateFormatter<\/code>.<\/p>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2023\/07\/21\/a-fast-timestamp-parser-in-swift\/\">A Fast Timestamp Parser in Swift<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2020\/10\/08\/date-format-change-in-app-store-receipts\/\">Date Format Change in App Store Receipts<\/a><\/li>\n<\/ul>\n\n<p id=\"iso8601dateformatter-and-fractional-seconds-update-2024-09-25\">Update (2024-09-25): <a href=\"https:\/\/mastodon.social\/@calicoding\/113189750737079829\">calicoding<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@calicoding\/113189750737079829\">\n<p><code>ISO8601DateFormatter<\/code> also isn&rsquo;t <code>Sendable<\/code> (but <code>DateFormatter<\/code> is) &#x1FAE0;. Makes it difficult to declare a shared instance for parsing dates from and API on a background thread.<\/p>\n<\/blockquote>\n\n<p>See also: <a href=\"https:\/\/mjtsai.com\/blog\/2024\/09\/23\/iso8601dateformatter-and-fractional-seconds\/#comment-4173614\">Ole Begemann<\/a>.<\/p>\n\n<p id=\"iso8601dateformatter-and-fractional-seconds-update-2025-11-19\">Update (<a href=\"#iso8601dateformatter-and-fractional-seconds-update-2025-11-19\">2025-11-19<\/a>): <a href=\"https:\/\/mastodon.social\/@chbeer\/115575647661154516\">Christian Beer<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@chbeer\/115575647661154516\">\n<p>Why the hell does <code>decoder.dateDecodingStrategy = .iso8601<\/code> not decode fractional seconds?! Why does the stupid <code>ISO8601DateFormatter<\/code> not decode all ISO8601 formats out of the box but needs to be configured to support valid ISO8601 formats?! &#x1F62B;<\/p>\n<\/blockquote>\n\n<p id=\"iso8601dateformatter-and-fractional-seconds-update-2025-12-23\">Update (<a href=\"#iso8601dateformatter-and-fractional-seconds-update-2025-12-23\">2025-12-23<\/a>): <a href=\"https:\/\/mastodon.social\/@dimitribouniol\/115763141801761373\">Dimitri Bouniol<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@dimitribouniol\/115763141801761373\">\n<p>TLDR, stop using <code>ISO8601DateFormatter<\/code>, it&rsquo;s <a href=\"https:\/\/gist.github.com\/dimitribouniol\/aea2e12be8e6c613891f96de856dfbfb\">pretty slow<\/a> compared to the modern <code>FormatStyle<\/code> alternatives[&#8230;]<\/p>\n<\/blockquote>","protected":false},"excerpt":{"rendered":"<p>Toomas Vahter: DateFormatter is used for converting string representation of date and time to a Date type and visa-versa. Something to be aware of is that the conversion loses microseconds precision. This is extremely important if we use these Date values for sorting and therefore ending up with incorrect order. Let&rsquo;s consider an iOS app [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2024-09-23T19:09:06Z","apple_news_api_id":"45c04cbc-33ff-4f75-af31-0a6b1f79860b","apple_news_api_modified_at":"2025-12-23T16:15:09Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAg==","apple_news_api_share_url":"https:\/\/apple.news\/ARcBMvDP_T3WvMQprH3mGCw","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[69,31,2586,30,2598,568,270,71,2854,901,364],"class_list":["post-45066","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-cocoa","tag-ios","tag-ios-18","tag-mac","tag-macos-15-sequoia","tag-nsdateformatter","tag-parser","tag-programming","tag-swift-foundation","tag-swift-programming-language","tag-time"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45066","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=45066"}],"version-history":[{"count":4,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45066\/revisions"}],"predecessor-version":[{"id":50545,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45066\/revisions\/50545"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=45066"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=45066"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=45066"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}