Show the "time since posted" for a social feed like Facebook/LinkedIn

I have been trying to figure out how to show a social feed that has a “time since posted” listed for each post. The goal was to have it be the same as Facebook or LinkedIn. If the post was 20 seconds old it would show “20s” if it was 3 hours old it would show “3h” and so on.

This is the definition of the data resources configured in the Data screen

My initial issue was figuring out how to do the calculation for a collection of records coming back from the server. It needs to be calculated each time for each object in the collection of records and can’t be something that is stored on the record. I do have a createdAt field that represents the time the post was created.

From that field, I needed to determine the difference between Now() and the createdAt time in milliseconds. With the milliseconds I used the javascript flow logic and added logic to determine if it should show as “2s”, “10m”, “2h”, “3d”,… You can see my javascript below that solved that problem. I looped through the collection of objects and updated the “duration” field with the calculated “time since post”.

All of that was pretty straightforward. My confusion was to figure out where to apply the javascript. I finally figured out that it needed to be attached right after the Get Record Collection data flow function. This is the data flow function that is associated with the Variables view on the page that I list all of the social posts in descending order by createdAt date.

This is what the social post list screen looks like. It isn’t finished by any means but I have the time since post working and thought I would share how it works. You can see the time since post shown on the right side of the app screen for each post in the list. The nice side-effect of how this worked is that the time will update as often as your collection of records flow is called (mine is set for 100ms)

I think I have shared the key details on how I got this to work. Feel free to ask questions.

Also, Let me know if you have a more straightforward technique for doing this. I can’t say that my approach is elegant, but for now it gets it done :slight_smile: I am new to Appgyver and it will be funny if there is just a setting or existing flow that does this automatically :flushed:

3 Likes

Nice work! If you could share your JavaScript code as copypasteable code here that would be helpful for others who want to implement the same thing.

This is something that should really be doable with formula functions but isn’t yet – essentially, we should implement https://momentjs.com/docs/#/displaying/fromnow/ as we are using Moment.js for datetime-related formulas anyway, with the option to configure the string representation of these.

Created a ticket at https://tracker.appgyver.com/feature-requests/p/implement-more-datetime-manipulationdisplaycalculation-formula-functions

1 Like
var index; var thePost; var posts = inputs.input1;

function timeSincePost(createdAt) {
var second = 1000;
var minute = 60000;
var hour = 3600000;
var day = 86400000;
var week = 604800000;
var month = 2628001152;
var year = 31536013824;
var timeSincePost = 0;
var timeSincePoststr = “”;

var timeDiffms = Math.abs(new Date() - new Date(createdAt));

if ((timeSincePost = Math.floor(timeDiffms / year)) > 0) {
timeSincePoststr = timeSincePost.toString() + “y”;
}
else if ((timeSincePost = Math.floor(timeDiffms / month)) > 0) {
timeSincePoststr = timeSincePost.toString() + “m”;
}
else if ((timeSincePost = Math.floor(timeDiffms / week)) > 0) {
timeSincePoststr = timeSincePost.toString() + “w”;
}
else if ((timeSincePost = Math.floor(timeDiffms / day)) > 0) {
timeSincePoststr = timeSincePost.toString() + “d”;
}
else if ((timeSincePost = Math.floor(timeDiffms / hour)) > 0) {
timeSincePoststr = timeSincePost.toString() + “h”;
}
else if ((timeSincePost = Math.floor(timeDiffms / minute)) > 0) {
timeSincePoststr = timeSincePost.toString() + “m”;
}
else if ((timeSincePost = Math.floor(timeDiffms / second)) > 0) {
timeSincePoststr = timeSincePost.toString() + “s”;
}
else {
timeSincePoststr = “now”
}

return timeSincePoststr;
}

for (index in inputs.input1)
{
posts[index][“duration”] = timeSincePost(posts[index].createdAt);
}

return { result: posts };

1 Like

@Steve_Stava Can you do a video showing a step-by-step implementation, got stuck at the JS level and setting the data variable.

@Harri_Sarsa Did you ever implement this? :point_up:t6:

Hi @Marvellous!
Can you share some screenshots, similar to the ones I have in my post? I can base my response/video on what you currently have. I appreciate your question and I am excited to get this working with you!

Thanks @Steve_Stava,
Here are my screen shorts

I added a JS script on the flow after Get record Method;

I copied your code to the Js Script node. It looks like the app variable did not get populated post_list.

Here is my schema.

When you paste my javascript, you will want to first paste it into a text editor without any formatting. I mention this because of the comparison of my quote marks and the quote marks in your example. Take a look at the screenshot comparisons below. Your quotes have the “mistake” squiggly line and you can see that mine are straight up and down and yours are “tilted”. This is probably because of how I shared the javascript code in my post.

If you paste my code into a text editor and make sure it is plain text and then paste it into the js flow function we might get you a little closer.

You will want to make sure all of your quotes in your js are correct :+1:

My quote marks…
image

Your quote marks…
image

This might not get everything working, but maybe it will :grinning:

1 Like


Well, this is meta, isn’t it!

1 Like

Dang! If I would’ve known enough when I originally posted that JavaScript and used that option I might’ve saved you some headaches :flushed:

2 Likes

Scratch that last thought. Turns out the same problem persists even with preformatted text. I reckon, when sharing code with quotation marks, we may need to place an asterisk and a note to replace all copy/pasted quotation marks with our own (type them in separately) in Composer.

Hey @Dominik_Greene, this is an old thread so I didn’t spot it before, but sounds like the DATETIME_DIFFERENCE() formula function (docs) could do the trick, if you firsŧ check for the difference between the posted time and NOW() in milliseconds, and then format the final result based on if that exceeds a minute, an hour, a day, etc. in milliseconds just like you do in the JS code.

Hi, Mari. We’re working to implement this right now. Unfortunately, the examples in the docs and the examples provided in the formula editor vary so wildly, it’s hard to tell what it actually wants us to do. I know the following formula code probably makes no sense, so any chance you could write us a sample example of what such a formula would look like. We’d like to compare the “current.created” time of a post pulled from the backend to the “NOW” (current time) and output text such as “a few seconds ago” for when, say, 10 seconds has passed.

So far, all we have it this disaster code: DATETIME_DIFFERENCE(current.created, NOW(), units: 10000 = “a few seconds ago”, indecimal: True) => 10000

Thank you. :slight_smile:

Hi @Dominik_Greene, if you take a look at the docs there are always some examples at the end (exactly the same ones exist also in the formula editor, you can see the whole formula if you horizontally scroll the box), for example:

DATETIME_DIFFERENCE("2019-07-11T13:06:15+03:00", "2018-07-11T13:06:15+03:00", "weeks", true)

Here’s one way you could format the time stamps:

1. How long has passed?

To make the time stamp text dynamic, first you’ll want to determine how many milliseconds have passed: DATETIME_DIFFERENCE(NOW(), current.created) As you can see in the first example in the docs, the last two parameters are unnecessary if you just want to get the milliseconds.

2. What units does this time correspond to?

Then you’ll need some additional logic to determine what units should be shown based on how long in milliseconds has passed. I would create an app variable of type List of objects for this with some initial values.

appVars.time = [{min: 0, max: 59999, units: "second"}, {min: 60000, max: 35999999, units: "minute"}] and so on for all the units. You can find the exact millisecond amounts for example by playing around with some mock dates in the editor, they were also included in a post earlier in this thread as JS.

When your “dictionary” of time units is done, you can take any time in milliseconds and compare it to the entries to see what kind of units you should be displaying by finding the entry where the current milliseconds fall between the minimum and maximum milliseconds allowed for that unit:

FIND(appVars.time, item.min <= DATETIME_DIFFERENCE(NOW(), current.posted) && item.max >= DATETIME_DIFFERENCE(NOW(), current.posted)).units

3. Display the result

Finally, you can use this formula inside another DATETIME_DIFFERENCE formula to display the time in the right units:

DATETIME_DIFFERENCE(NOW(), current.posted, FIND(appVars.time, item.min <= DATETIME_DIFFERENCE(NOW(), current.posted) && item.max >= DATETIME_DIFFERENCE(NOW(), current.posted)).units, false)

2 Likes

Thanks for this, @Mari Mari! A huge help in figuring out what to do. Working to implement right now.

As a side note, I’m not sure if this is a bug, but with an app variable as a list, you don’t seem to be able to assign initial values to the children text fields inside – whereas you can for standalone app variables. It seems we might have to go that route. Could be visually messy. :slight_smile:

Hi, yes you should be able to do that by choosing the top level variable and filling in some entries:

1 Like

I see now. You’re a sanity-saver. That does, indeed, work and you saved me from formatting the whole list incorrectly with your screenshot. Thank you! :slight_smile:

1 Like

Okay, awesome. It appears, after much brainstorming, I’ve actually got this done correctly, save for one thing. While I do have a near-realtime time counter now for each post in the list, it shows just the appropriate number specifying seconds, minutes, hours, etc. But is there any way to actually make it display the ‘units’ as well so that it reads “3 minutes ago” instead of “3 ago”?

To be clear, I’ve already added a + "\u00a0ago" to the formula, but I’m not sure how to bring in the actual unit of time. In other words, my formula currently looks like:
DATETIME_DIFFERENCE(NOW(), repeated.current.created, FIND(appVars.timeSince, item.min <= DATETIME_DIFFERENCE(NOW(), repeated.current.created) && item.max >= DATETIME_DIFFERENCE(NOW(), repeated.current.created)).units, false) + "\u00a0ago"

Any thoughts?

And thank you, @Mari. That worked otherwise perfectly! :slight_smile:

1 Like

Hi @Dominik_Greene, that’s what this formula does essentially (get the units string), so you can just add it to the end again :slight_smile:

1 Like

Thank you, Mari. I didn’t realize the formula code needed to be duplicated. It works perfectly now.

I also like that I can set up the units with milliseconds to be grammatically-correct, i.e. 1 minute ago vs. 1 minutes ago. Worked with everything except “1 seconds ago”, but I’m not going to nitpick there. :slight_smile:

1 Like