2

Actual string - January 31, 2020 at 11:59:59 p.m. (ET). format - "MMMM d, yyyy 'at' hh:mm:ss aa" Not able to convert this string to Date object. Tried various date format and but unable to change string to Date object. Please help

vadian
  • 274,689
  • 30
  • 353
  • 361
Sumit Jangra
  • 651
  • 5
  • 16

2 Answers2

1

You could delete the non-standard character . between p and m and escape the parentheses around the time zone

let dateString = "January 31, 2020 at 11:59:59 p.m. (ET)"
let trimmedDateString = dateString.replacingOccurrences(of: ".m.", with: "m")
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "MMMM d, yyyy 'at' hh:mm:ss a (v)"
let date = formatter.date(from: trimmedDateString)
vadian
  • 274,689
  • 30
  • 353
  • 361
  • It would be easier to set a custom am and pm symbols `formatter.pmSymbol = "p.m."` https://stackoverflow.com/a/31469237/2303865 – Leo Dabus Feb 05 '20 at 12:34
  • @LeoDabus Yes, I know, but this considers `am` and `pm` – vadian Feb 05 '20 at 12:36
  • Considering that's a custom format it should not vary – Leo Dabus Feb 05 '20 at 12:37
  • What about using `NSDataDetector`? We wouldn't have to use the p.m. & p.m & the parenthesis... – Larme Feb 05 '20 at 12:53
  • In playground i can convert this string to date object but in project i can't. Also pm am ET i removed them all but still datestring not convert into date object. – Sumit Jangra Feb 05 '20 at 13:27
  • @SumitDhariwal don't remove the timezone from your string. If you escape it the timezone will be ignored when parsing your date. – Leo Dabus Feb 05 '20 at 13:32
0
let raw = "January 31, 2020 at 11:59:59 p.m. (ET)"

func getDateFrom(_ raw: String) -> Date? {

    if let i = (raw.range(of: "(")?.lowerBound) { // get index of open parenthesis

        var zone: TimeZone?
        let dateString = String(raw.prefix(upTo: i)) // January 31, 2020 at 11:59:59 p.m.
        let zoneString = String(raw.suffix(from: i)) // (ET)

        switch zoneString { // determine time zone

        case "(ET)", "(EST)", "(EDT)": // study your data source and learn how they may express time zones
            zone = TimeZone(abbreviation: "EDT")

        default:
            return nil // failure

        }

        let formatter = DateFormatter()
        formatter.dateFormat = "MMMM d, yyyy 'at' hh:mm:ss a"
        formatter.timeZone = zone
        formatter.amSymbol = "a.m."
        formatter.pmSymbol = "p.m."

        if let date = formatter.date(from: dateString) {
            return date
        } else {
            return nil
        }

    } else {
        return nil
    }

}

if let date = getDateFrom(raw) {
    print(date) // 2020-02-01 04:59:59 +0000
}

This should be a good starting point. There are a number of ways to do this, such as whether you want it to fail if a time zone can't be determined, how to extract the time zone (using abbreviations, identifiers, seconds from GMT), etc. I like vadian's answer if I was completely comfortable with the time zone. But time zones are so inconsistent and surprisingly non-standardized when expressed as strings, that I'd rather dedicate a mechanism to getting it and making sure it's valid.

That said, this is a relatively crude example of where I'd begin—a finished version would be more nuanced. In this example, if the time zone fails, the function fails.

trndjc
  • 11,654
  • 3
  • 38
  • 51