Медленный DateFormatter и альтернатива


#1

Привет!

Необходимо обработать большой массив дат, и соответственно важна скорость. Как выяснилось,

let date = dateFormatter.date(from: dateString)

работает очень медленно. В гугле нашел аналоги на С: strptime() и vsscanf() (здесь подробнее http://jordansmith.io/performant-date-parsing/). Автору больше нравится вторая, но первая у меня оказалась в полтора раза быстрее. В другом месте (https://gist.github.com/robnadin/f3cfd06095b085f5e132) нашел немного более лучшую реализацию и актуализировал код:

extension Date {
    
    static func dateFromISO8601String(_ string: String) -> Date? {
        var tm = Darwin.tm()
        strptime(string.cString(using: .utf8)!, "%Y%m%d %H%M%S", &tm)
        tm.tm_isdst = -1
        return Date(timeIntervalSince1970: TimeInterval(mktime(&tm) + TimeZone.current.secondsFromGMT()))
    }
}

Проблема в том, что сравнивая результаты парсинга (dateFormatter vs strptime), даты отличаются на 1 час (где-то с марта по октябрь), что скорее всего связано с day light saving. Как это можно учесть в коде?


#2

А как даты представлены?
Их просто отсортировать нужно?


#3

Даты представлены в формате yyyyMMdd HHmmss, например 20071231 190100. Их я считал из файла (вместе с другими данными) и просто заношу в массив для дальнейшей работы.


#4

Так а в чем задача? В сортировке? почему нельзя привести к формату date и сравнивать?


#5

Возможно с этого и стоило начать. Мб проблема именно в необходимости обрабокти большого набора данных? Попробуйте:

  • разбить его
  • распараллелить
  • мб хранение не единым файлом тоже даст свои плоды

#6

Задача в том, чтобы получать дату из строки быстрее, исправив функцию dateFromISO8601String - чтобы всегда были корректные даты (в период с марта по октябрь полученная дата отличается на один час по сравнению с датой, полученной от dateFormatter).

В файле 4 млн строк с датами. Я загружаю файл и обрабатываю каждую строку

let csv = try String(contentsOf: url, encoding: .utf8)

var dates: [Date] = []
dateFormatter.dateFormat = “yyyyMMdd HHmmss”

csv.enumerateLines { line, stop in

let date = dateFormatter.date(from: line) // очень долго
let dateFast = Date.dateFromISO8601String(line) // по времени гораздо лучше
// но где-то отличается на один час, как это исправить?

if date != dateFast { print(date, dateFast) }

dates.append(dateFast)
}