0

Using the following overly complex code a date can almost be extracted from a string:

let dateStringArray:[String] = ["29-01-2017 10:41:18:825325012","29-01-2017 10:41:18:894631028"]
let formatString = "dd-MM-yyyy HH:mm:ss:nnnnnnnnn"
let dayRange = formatString.range(of: "dd")
let monthRange = formatString.range(of: "MM")
let yearRange = formatString.range(of: "yyyy")
let hourRange = formatString.range(of: "HH")
let minuteRange = formatString.range(of: "mm")
let secondRange = formatString.range(of: "ss")
let nanoRange = formatString.range(of:"nnnnnnnnn")

let dateString = dateStringArray[0]


let dateComponents = DateComponents( year:Int(dateString.substring(with: yearRange!)),
                                     month:Int(dateString.substring(with: monthRange!)),
                                     day:Int(dateString.substring(with: dayRange!)),
                                     hour:Int(dateString.substring(with: hourRange!)),
                                     minute:Int(dateString.substring(with: minuteRange!)),
                                     second:Int(dateString.substring(with: secondRange!)),
                                     nanosecond:Int(dateString.substring(with: nanoRange!)))
let nano = Int(dateString.substring(with: nanoRange!))
let currentCalendar = Calendar.current
let dateExtracted = currentCalendar.date(from: dateComponents)
print("\(dateExtracted!)")

The output from the final print is: "2017-01-29 10:41:18 +0000\n"

There are issues with this (1) there must be an easier way. (2) & more important, why is the nanosecond component apparently not appearing?

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
eklektek
  • 1,083
  • 1
  • 16
  • 31

1 Answers1

1

(1) there must be an easier way

Use a date formatter:

let dateString = "29-01-2017 10:41:18:825325012"

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss:SSSSSSSS"

let dateExtracted = dateFormatter.date(from: dateString)!

(2) why is the nanosecond component apparently not appearing?

The description method of Date does not show fractional seconds, but you can extract it again with

currentCalendar.component(.nanosecond, from: dateExtracted!)

The result may be slightly different from the original nanosecond value in the string due to rounding errors, because Date stores internally a floating point number (number of seconds since the reference date Jan 1, 2001). If you use a date formatter as suggested above then the resolution is limited to milliseconds (compare NSDateFormatter milliseconds bug).

Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Works thanks. The use of .nanosecond is misleading if the actual precision is milliseconds. The nanosecond value was extracted from Date() in the first instance! Where can I find the reference informing the use of SSSSSSSSS for sub-seconds? – eklektek Feb 01 '17 at 20:28
  • @user2196409: http://unicode.org/reports/tr35/tr35-dates.html#dfst-second – Martin R Feb 01 '17 at 20:32
  • @user2196409: A `Date` is internally represented as a floating point number (Double) and therefore has limited precision. If you try your code with `"29-01-2017 10:41:18:825325014"` then the extracted nanoseconds are still `825325012`. So you cannot expect that nanoseconds are always preserved exactly. (If you need that then use `DateComponents` and not `Date`). – `DateFormatter` has the additional "bug" that it works only up to milli-seconds. If that is a problem then don't use DateFormatter. – Martin R Feb 01 '17 at 20:36