Как заменить дату в строке на дату, читаемую человеком в Swift?

#ios #swift

Вопрос:

У меня есть строка, которую я получаю с сервера, которая выглядит так:

 You blocked until 2022-01-01T11:00:00.350Z
 

И теперь я хочу преобразовать его в удобочитаемую дату, например

 2022-01-01 11:00
 

Для этого я сначала попытался найти дату:

 let types: NSTextCheckingResult.CheckingType = [.date]
if let detector = try? NSDataDetector(types: types.rawValue) {
  let range = NSMakeRange(0, message.count)
  let matches = detector.matches(in: message, 
options: NSRegularExpression.MatchingOptions(rawValue: 0), 
range: range)

if !matches.isEmpty {
   for match in matches {
      print(match.date)

      let aSubstring = NSString(string: message).substring(with: match.range)
      print(aSubstring)
   }
}
}
 

Так что в результате match.date меня вернули 2022-01-01 11:00:00 0000 , но результат aSubstring есть until 2021-08-02T11:38:10.214Z .
Поэтому мне любопытно, почему он включается until в подстроку и как я могу этого избежать?

Комментарии:

1. @мэтт, спасибо тебе! Не могли бы вы, пожалуйста, помочь мне с регулярным выражением для этой 2022-01-01T11:00:00.350Z строки? Я так плохо разбираюсь в регулярных выражениях и не могу открыть еще один вопрос SO в течение следующих 90 минут. Я была бы так благодарна!

2. На самом деле, если это всегда последнее слово фразы, вам вообще не нужно регулярное выражение или поиск.

Ответ №1:

Возможное решение состоит в том, чтобы извлечь строку ISO8601, опуская секунды, дробные секунды и часовой пояс с помощью регулярного выражения, а затем получить первые 10 (дата) и последние 5 символов (время).

 let string = "You blocked until 2022-01-01T11:00:00.350Z"
if let range = string.range(of: "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}", options: .regularExpression) {
    let trimmedString = String(string[range])
    let humanReadable = "(trimmedString.prefix(10)) (trimmedString.suffix(5))"
    print(humanReadable) // 2022-01-01 11:00
}
 

Однако есть одно предостережение: дата указана в UTC. Если вы хотите, чтобы дата отображалась в текущем часовом поясе, вам необходимо использовать форматер даты (на самом деле два).

 let string = "You blocked until 2022-01-01T11:00:00.350Z"
if let range = string.range(of: "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}", options: .regularExpression) {
    let trimmedString = String(string[range])   "Z"
    let inputFormatter = ISO8601DateFormatter()
    if let date = inputFormatter.date(from: trimmedString) {
        let outputFormatter = DateFormatter()
        outputFormatter.locale = Locale(identifier: "en_US")
        outputFormatter.dateFormat = "yyyy-MM-dd HH:mm"
        let humanReadable = outputFormatter.string(from: date)
        print(humanReadable)
    }
}
 

Ответ №2:

если часть даты находится в конце строки, то вы могли бы попробовать что-то более сложное, но выполнимо. Что-то вроде этого:

 struct ContentView: View {
    @State var txt = ""

    func humanDate(_ str: String) -> String? {
        // convert the string to a date
        let dateFormatter1 = DateFormatter()
        dateFormatter1.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        // re-format the date to your liking
        if let date = dateFormatter1.date(from: str) {
            let dateFormatter2 = DateFormatter()
            dateFormatter2.dateFormat = "yyyy-MM-dd HH:mm"
    // dateFormatter2.dateFormat = "yyyy MMMM EEEE HHa:mm" // even more human readable                
            return dateFormatter2.string(from: date)
        } else {
            return nil
        }
    }
    
    var body: some View {
        Text(txt).onAppear {
            
            let inputString = "You blocked until 2022-01-01T11:00:00.350Z"
            if let dateStr = inputString.split(separator: " ").last {
                if let theDate = humanDate(String(dateStr)) {
                    print("n----> "   theDate   "n")
                    txt = theDate
                }
            }
            
        }
    }
}