DateFormatter rounds a time to milliseconds

Hi there!

I'm trying to parse a date and time with microseconds using DateFormatter. However the obtained instance of Date class holds the time rounded off to milliseconds.

I can show it with this code:

import Foundation

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"

let date = formatter.date(from: "2022-02-01T19:35:49.987654")!

print(formatter.string(from: date))
print(Calendar.current.component(.nanosecond, from: date))

The output is:

2022-02-01T19:35:49.987000
986999988

So 987654 microseconds were rounded off to 987 milliseconds and I don't understand why.

What am I doing wrong and how to fix it?

Thanks in advance.

P.S. swift version:

swift-driver version: 1.26.21 Apple Swift version 5.5.2 (swiftlang-1300.0.47.5 clang-1300.0.29.30)
Target: x86_64-apple-macosx12.0

I think DateFormatter is parsing with ICU, which may only support millisecond precision.

(Search for __cficu_ucal_getMillis and __cficu_ucal_setMillis in CFDateFormatter.c)

1 Like

Indeed, this is a current limitation of the underlying ICU library (for long-standing backwards-compatibility reasons); from the udat.h docs:

UDAT_FRACTIONAL_SECOND_FIELD

FieldPosition and UFieldPosition selector for 'S' field alignment, corresponding to the UCAL_MILLISECOND field.

Note: Time formats that use 'S' can display a maximum of three significant digits for fractional seconds, corresponding to millisecond resolution and a fractional seconds sub-pattern of SSS. If the sub-pattern is S or SS, the fractional seconds value will be truncated (not rounded) to the number of display places specified. If the fractional seconds sub-pattern is longer than SSS, the additional display places will be filled with zeros.

1 Like

What others have said but also…

If you continue to use DateFormatter to parse fixed-format date strings, make sure to pin the locale to en_US_POSIX. See QA1480 NSDateFormatter and Internet Dates for an explanation as to why this is important.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

4 Likes

It seems I should not use DateFormatter in this case. I'll parse a date with a regular expression.
Thank you!

Are there any updates to this? I'm having the same issue where my Swift.Date ISO8601 round-trip coding is not lossless.
I'm observing the millisecond rounding.

Are there any other existing solutions for ISO8601 encoding/decoding that are lossless with Swift.Date?

There's an issue for this: ISO8601FormatStyle produces unexpected results when including fractional seconds · Issue #963 · swiftlang/swift-foundation · GitHub

1 Like