0

I have my created_at in String (in form of 2015-12-16 19:28:16). I want to compare it to the current time and give time difference in a form of 5h, 35m, 3d etc...

I have found on a SO answer that I can use an extension to achieve that. This is the extension:

extension NSDate {
    func yearsFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Year, fromDate: date, toDate: self, options: []).year
    }
    func monthsFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Month, fromDate: date, toDate: self, options: []).month
    }
    func weeksFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.WeekOfYear, fromDate: date, toDate: self, options: []).weekOfYear
    }
    func daysFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Day, fromDate: date, toDate: self, options: []).day
    }
    func hoursFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Hour, fromDate: date, toDate: self, options: []).hour
    }
    func minutesFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Minute, fromDate: date, toDate: self, options: []).minute
    }
    func secondsFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Second, fromDate: date, toDate: self, options: []).second
    }
    func offsetFrom(date:NSDate) -> String {
        if yearsFrom(date)   > 0 { return "\(yearsFrom(date))y"   }
        if monthsFrom(date)  > 0 { return "\(monthsFrom(date))M"  }
        if weeksFrom(date)   > 0 { return "\(weeksFrom(date))w"   }
        if daysFrom(date)    > 0 { return "\(daysFrom(date))d"    }
        if hoursFrom(date)   > 0 { return "\(hoursFrom(date))h"   }
        if minutesFrom(date) > 0 { return "\(minutesFrom(date))m" }
        if secondsFrom(date) > 0 { return "\(secondsFrom(date))s" }
        return ""
    }
}

So I can use dateWithEra() and call offsetFrom():

let date4 = NSCalendar.currentCalendar().dateWithEra(1, year: 2015, month: 11, day: 28, hour: 5, minute: 9, second: 0, nanosecond: 0)!

let timeOffset3 = NSDate().offsetFrom(date3) // "54m"

However, I want to give it a date in String.

let myDate = post!["created_at"].string! // 2015-12-16 19:28:16

How can I give it a String to be able to convert 3h, 30m? I think I can exploit the string and place it in dateWithEra, but is there a way of giving it a string directly?


Or am I completely out of track? What I want to achieve is getting the time difference between a date in a string (in 2015-12-16 19:28:16 format) and current time and present it as "5h" or "50m".

Community
  • 1
  • 1
senty
  • 12,385
  • 28
  • 130
  • 260

1 Answers1

1

To get NSDate from a formatted string use NSDateFormatter

let dateString = "2015-12-16 19:28:16"
let inputFormatter = NSDateFormatter()
inputFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
let date = inputFormatter.dateFromString(dateString)!

If you can live with min instead m for the minutes abbreviation in some localizations, the easiest way is NSDateComponentsFormatter

let outputformatter = NSDateComponentsFormatter()
outputformatter.allowedUnits = [.Day, .Hour, .Minute, .Second]
outputformatter.unitsStyle = .Abbreviated
let timeOffset = outputformatter.stringFromDate(date, toDate: NSDate())!

Edit:

To get always m rather than min, make timeOffsetmutable and add

var timeOffset = outputformatter.stringFromDate(date, toDate: NSDate())!
if let minRange = timeOffset.rangeOfString("in") {
    timeOffset = timeOffset.substringToIndex(minRange.startIndex) + timeOffset.substringFromIndex(minRange.endIndex)
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • What if I want to use `m` instead of `min`? Can you please also include that just for learning? Cheers – senty Dec 17 '15 at 10:55
  • It depends on the locale, on a US locale you will get `m`. If you get `min` and you want to have `m`, you have to trim the returned string. – vadian Dec 17 '15 at 10:58
  • var timeOffset is returning : "1,340d 1h 7m 35s" successfully, thanks a lot. Just out of curiosity, I didn't understand what the if statement actually doing. I couldn't get it inside the closure – senty Dec 17 '15 at 11:37
  • 1
    The if statement checks if the output string contains `in` (without leading `m)`. If yes, create a new string which cuts out the `in` – vadian Dec 17 '15 at 11:59
  • Ah ace! I think it will always convert to m instead of min, so it's working fine! Thanks a lot. Just another curiosity, what if I want to use 2mo instead of 60d. I tried adding: [.Month, .Day, .Hour, .Minute, .Second], but it failed so badly. Thanks a lot!! – senty Dec 17 '15 at 12:08
  • Actually it's supposed to work also with `.Month`. I get another lowercase `m` for the month on a US locale and a uppercase `M` on a DE locale. – vadian Dec 17 '15 at 12:26