0

I get my data from an API which received the data as strings.

I have NSString type variable name timeAgo which represents the unix time in seconds (for example: 1455893366). My goal is to change it to "X minutes/hours/days ago" format.

I've couldn't find something useful, and I don't want to change my API to do it (Well, im learning Objective-C and iOS..).

Anyone can help me how it can be done?

I've been trying: int interval = (int) ([[NSDate date] timeIntervalSinceDate:update.timeAgo] / 3600); but I get the following error: Incompatible pointer types sending 'NSString *' to parameter of type 'NSDate * _Nonnull'

Elikos
  • 103
  • 1
  • 10
  • 1
    So you want someone here to write that for you? That isn't how it works. Attempt a solution yourself first and then come back with specific questions. – trojanfoe Feb 19 '16 at 14:59
  • 2
    Possible duplicate of [iPhone: Convert date string to a relative time stamp](http://stackoverflow.com/questions/902950/iphone-convert-date-string-to-a-relative-time-stamp) – Larme Feb 19 '16 at 15:01
  • You can also search [here](http://stackoverflow.com/questions/1739383/convert-seconds-integer-to-hhmm-iphone) before posting a question: – Craig Smith Feb 19 '16 at 15:01
  • @Larme The solution there gets me an error: `ARC forbids explicit message send of 'release'`, @Craig Smith it has nothing to do with unix time – Elikos Feb 19 '16 at 15:04
  • Well, remove the `release` calls. – Larme Feb 19 '16 at 15:06
  • If you're just learning, you need to break complex problems into simpler ones: How to get numeric value from a string representation. How to convert a number Unix time to a date-time object. How to convert a date-time object to an interval between date-time objects (with "now" being the other). How to format an interval into a string like "X Hours ago". Research those individually and ask questions about the steps where you encounter specific problems. – Ken Thomases Feb 19 '16 at 23:10

2 Answers2

1

First, turn the string into a number like this:

let timestamp = NSTimeInterval(timeAgo)

Then, you can use a function like this to format it as a relative string:

var currentUnixTime: NSTimeInterval { return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970 }

func relativeStringForUnixTime(time: NSTimeInterval) -> String {
    struct Static {
        static var once: dispatch_once_t = 0
        static var formatter: NSDateComponentsFormatter!
    }
    dispatch_once(&Static.once) {
        Static.formatter = NSDateComponentsFormatter()
        Static.formatter.allowedUnits = [ .Day, .Hour, .Minute, .Second ]
        Static.formatter.maximumUnitCount = 1
        Static.formatter.unitsStyle = .Full
    }

    let offset = currentUnixTime - time
    if offset > 0 {
        return Static.formatter.stringFromTimeInterval(offset)! + " ago"
    } else {
        return Static.formatter.stringFromTimeInterval(-offset)! + " from now"
    }
}

relativeStringForUnixTime(currentUnixTime)          // "0 seconds ago"
relativeStringForUnixTime(currentUnixTime - 10)     // "10 seconds ago"
relativeStringForUnixTime(currentUnixTime - 100)    // "2 minutes ago"
relativeStringForUnixTime(currentUnixTime - 1000)   // "17 minutes ago"
relativeStringForUnixTime(currentUnixTime - 10000)  // "3 hours ago"
relativeStringForUnixTime(currentUnixTime - 100000) // "1 day ago"

relativeStringForUnixTime(currentUnixTime + 10)     // "9 seconds from now"
relativeStringForUnixTime(currentUnixTime + 100)    // "2 minutes from now"
relativeStringForUnixTime(currentUnixTime + 1000)   // "17 minutes from now"
relativeStringForUnixTime(currentUnixTime + 10000)  // "3 hours from now"
relativeStringForUnixTime(currentUnixTime + 100000) // "1 day from now"
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Nice function, but... The OP states "I'm learning Objective-C"; they have a string as input - which is the cause of the error they show; and their input is a UNIX time so your function is 31 years out. – CRD Feb 19 '16 at 18:06
  • You're right. I should have paid more attention. Fixed. – rob mayoff Feb 19 '16 at 21:27
1

im learning Objective-C and iOS

Well let's see if we can help you along, without just giving the final answer.

The code you tried:

int interval = (int) ([[NSDate date] timeIntervalSinceDate:update.timeAgo] / 3600);

gives you the error:

Incompatible pointer types sending 'NSString *' to parameter of type 'NSDate * _Nonnull'

You've already stated that timeAgo is an NSString *, that is some text. Computers represent text and numbers differently, e.g. the string @"42" is represented differently to the integer 42, and also to the floating-point number 42.0.

As you just have the textual representation of a number the first thing you need to do is produce the equivalent actual number, which you might store in a variable of type int, long, double etc. depending on the magnitude of the number you expect.

Which type should you pick? Well Cocoa uses the type NSTimeInterval to represent a time interval in seconds, and if you follow the link you'll find it is just a convenient name for double so that would be a good choice.

Now look at the NSString documentation for a method which parses (interprets) your text as a double value and returns the result.

So now you have your seconds as a double (or NSTimeInterval). But that won't completely address the error as the message says a value of type NSDate * (ignore the _Nonnull for now, you can learn about that in the future). Computers use different representations for different types, not just for text and numbers, and here you need an NSDate * value, a double (aka NSTimeInterval - don't forget) will do you no better than the NSString * did.

Rather than figure out how to produce an NSDate value from an NSTimeInterval, in this case there is a more direct way. You selected the method timeIntervalSinceDate why? Take another look at the NSDate documentation. You are interested in time differences, or intervals, not in absolute dates. You have a Unix time interval, which is a number of seconds, and you wish to know the number of seconds it differs from now. This should suggest you wish to be generating/adding/subtracting/comparing NSTimeInterval values, and there are some methods in NSDate which take/return NSTimeInterval values.

Before you go any further you need to understand about how time is measured on Unix and OS X. Unix stores time as the number of seconds since the Unix epoch, which is the very start (00:00) of the 1st Jan 1970 in the UTC time zone. OS X also stores time as the number of seconds since the epoch, however the OS X epoch is the start of 1st Jan 2001. What this means is you must be careful that given two NSTimeInterval values that they are based on the same epoch, if not your calculations might have an error of 31 years!

Can you find a method in NSDate which will give you now as a Unix time, that is an NSTimeInterval counting from 1970?

Got it? You can take the difference between your Unix time (which came from timeAgo and you've converted to double/NSTimeInterval) and the Unix time for now (from NSDate methods) and you've got the number of seconds you wish to convert to "X minutes/hours/days ago" format. (Note: if you might have future times you'll need to be aware of the sign of the difference, if only past times just subtract in the right order so you always get a positive difference.)

So the next step, how do you convert your seconds to the text phrase you want? Provided you're on at least iOS 8 there is a class NSDateComponentsFormatter which can convert values of type NSDateComponents (hence the class name) and NSTimeInterval to the kind of text you want. Just read the documentation and you'll figure it out.

If you follow this through, produce some code, and still have problems you can ask a new question, showing your new code, and explaining why you are stuck. Someone will probably help you along.

(Note: You don't say if you know other programming languages; if you do apologies if some of the above is a bit basic for you, also if you get stuck you might want to "cheat" and look at Rob's answer which is written in Swift and covers much of what is said above.)

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86