PREVIEW
Sometimes you would want to show your users a notification on their Dashboard, with the date the notification was created.
You can easily do that by subtracting the current TIMESTAMP from the TIMESTAMP of the date the notification was created.
But here's the big deal, you would only get the exact minutes if its a new notification, until an hour elapses then the minutes resets back to zero (0).
HOW DO I GO ABOUT IT?
I will show you an easy way to go around this problem. Let's begin with JavaScript.
JS
You should be familiar with the JavaScript date methods because we are going to need it. If you wish to refresh your memory on it, click here to visit w3Schools.
STEP 1
We will term the date the notification was sent as date notified.
- Create a function that accepts the date notified as a parameter.
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
}
- Find the TIMESTAMP of date_notified
We can find the TIMESTAMP of the date (date_notified) using getTime() method. To do that, we will create a variable that will instantiate a new Date() object and then pass date_notified as a parameter.
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
var date_sent_tmp = new Date(date_notified);
var date_sent = date_sent_tmp.getTime();
}
But what if you passed A Timestamp as a parameter instead of an actual Date?
We can edit our function to check for such using indexOf() method.
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
var date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
}
Here, if a TIMESTAMP is found, it will use the Timestamp, but if none is found, it will convert the date provided to its Timestamp.
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
}
- Let's subtract the notified date TIMESTAMP from the current TIMESTAMP
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
}
- A Little Problem
Our calculation (calc) works correctly but there's a little problem. JavaScript adds extra (+1 hr) to the result from our calculation and the case might be different if you're on another Timezone.
From the Image Above, the time circled red is the date the notification was created. The time circled blue, is the current date as at when I tested the code and the Time highlighted yellow is the result from our subtraction.
Using simple maths, subtracting 15:00:00 from 16:09:28 should give us exactly 1:09:28 But instead, an extra 1 Hour was added to the result.
16:09:28 - 15:00:00 = 1:09:28
- A Little Solution
In order to go around this, we have to convert the hour from the result to UTC ( universal Time Cordinated ) then add zero (0) to it.
We will use the method getUTCHours() to retrieve the UTC hour from the calculation, add zero to it and then set the hour of the calculation to the result of our expression.
It looks lengthy right? But don't worry, it's easy!
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
//Prevent Extra 1 Hour
calc.setHours( calc.getUTCHours() +0);
}
STEP 2
Let's get ready to show the results to our users
We have succeeded in finding the difference between the two Timestamps, and preventing an Extra Hour from being added. Now we have to make the result of our calculation readable, which will be in; days, months, years, hours, minutes and seconds.
We will create 2 variables for this.
The first variable will store the date, month and year in the format (" d - m - y " ). The second variable will store the Hours, minutes, and seconds in the format ( " H : m : s " ).
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
//Prevent Extra 1 Hour
calc.setHours( calc.getUTCHours() +0);
//Make our result readable
var calcDate = calc.getDate()+'-'+(calc.getMonth()+1)+'-'+calc.getFullYear(); //25-12-2021
var calcTime = calc.getHours()+':'+calc.getMinutes()+':'+calc.getSeconds(); //15:00:00
}
We're using the Date() methods to retrieve the exact details we need from our calculation.
- JavaScript getMonth() method
Am sure you didn't notice that we added an extra 1 to the getMonth() method. This is because, in JavaScript, months are counted from 0 (January) up to 11 (December).
So if you did something like ;
const dt =new Date();
console.log(dt.getMonth());
The output would be
As we know, November is the 11th month. But in JavaScript Date() object, it is the 10th month. So we had to add an Extra 1 to the month to make it more understandable.
- Let's carry on
Next, we have to convert our calcDate which is the resultant date from our calculation to an array, so that we can easily access its properties and then store the properties to variables (date_passed and time_passed).
We will use the split() method for this.
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
//Prevent Extra 1 Hour
calc.setHours( calc.getUTCHours() +0);
//Make our result readable
var calcDate = calc.getDate()+'-'+(calc.getMonth()+1)+'-'+calc.getFullYear(); //25-12-2021
var calcTime = calc.getHours()+':'+calc.getMinutes()+':'+calc.getSeconds(); //15:00:00
//Get How many days, months and years that has passed
var date_passed = calcDate.split("-");
var time_passed = calcTime.split(":");
}
- Another thing you should know
JavaScript shows a Timestamp according to the number of milliseconds that has elapsed since 1st Jan, 1970. You should look out for this right here.
When the result from our calculation shows 25 secs ago or 2 hrs 30 mins ago, you should also expect to see the date as 1-1-70 because the time from our calculation hasn't been up to a day yet, so JavaScript will use the default date available.
Just like the image above, the value circled red is the result from our calculation as 6 hrs 20 mins ago which isn't up to a day, so the default date has to be used.
- Why is this Important?
This is because;
We will subtract each of the default dates from the results of our calculation to find the exact days, months and years that has passed since the notification was sent so that we don't display the default dates to our end users.
We can access the arrays one after the other since we had them created in these formats ("d-m-y") and ("H:i:s");
So;
date_passed at position 0 is the day. (date_passed[0])
date_passed at position 1 is the month. (date_passed[1])
date_passed at position 2 is the year. (date_passed[2])
Likewise;
time_passed at postion 0 is the Hour. (time_passed[0])
time_passed at position 1 is the Minutes. (time_passed[1])
time_passed at position 2 is the seconds. (time_passed[2])
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
//Prevent Extra 1 Hour
calc.setHours( calc.getUTCHours() +0);
//Make our result readable
var calcDate = calc.getDate()+'-'+(calc.getMonth()+1)+'-'+calc.getFullYear(); //25-12-2021
var calcTime = calc.getHours()+':'+calc.getMinutes()+':'+calc.getSeconds(); //15:00:00
//Get How many days, months and years that has passed
var date_passed = calcDate.split("-");
var time_passed = calcTime.split(":");
if(!(date_passed.includes('1-1-1970'))) {
var days_passed = ((parseInt(date_passed[0]) - 1) != 0 ) ?
parseInt(date_passed[0]) - 1 : null;
var months_passed = ((parseInt(date_passed[1]) - 1) != 0 )?
parseInt(date_passed[1]) - 1 : null;
var years_passed = ((parseInt(date_passed[2]) - 1970) != 0) ?
parseInt(date_passed[2]) - 1970 : null;
}else{
var days_passed = null;
var months_passed = null;
var years_passed = null;
}
var hours_passed = parseInt(time_passed[0]);
var mins_passed = parseInt(time_passed[1]);
var secs_passed = parseInt(time_passed[2]);
}
- We are almost there
Let's set up our custom text such as 1 sec ago, or 50 secs ago, taking note of the singular and plural forms
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
//Prevent Extra 1 Hour
calc.setHours( calc.getUTCHours() +0);
//Make our result readable
var calcDate = calc.getDate()+'-'+(calc.getMonth()+1)+'-'+calc.getFullYear();
var calcTime = calc.getHours()+':'+calc.getMinutes()+':'+calc.getSeconds();
//Get How many days, months and years that has passed
var date_passed = calcDate.split("-");
var time_passed = calcTime.split(":");
if(!(date_passed.includes('1-1-1970'))) {
var days_passed = ((parseInt(date_passed[0]) - 1) != 0 ) ?
parseInt(date_passed[0]) - 1 : null;
var months_passed = ((parseInt(date_passed[1]) - 1) != 0 )?
parseInt(date_passed[1]) - 1 : null;
var years_passed = ((parseInt(date_passed[2]) - 1970) != 0) ?
parseInt(date_passed[2]) - 1970 : null;
}else{
var days_passed = null;
var months_passed = null;
var years_passed = null;
}
var hours_passed = parseInt(time_passed[0]);
var mins_passed = parseInt(time_passed[1]);
var secs_passed = parseInt(time_passed[2]);
//Set up your Custom Text output here
const s = ["sec ago", "secs ago"];
const m = ["min", "sec ago", "mins", "secs ago"];
const h = ["hr", "min ago", "hrs", "mins ago"];
const d = ["day", "hr ago", "days", "hrs ago"];
const M = ["month", "day ago", "months", "days ago"];
const y = ["year", "month ago", "years", "months ago"];
}
The first array will be for results like 1 sec ago or 25 secs ago The second array will be for results like 1 min ago or 25 mins ago ... (and so on) The last array will be for results like 1 year 1 month ago or 2 years 5 months ago.
- Final Step
Let's figure out the variables that are empty and then set our return value to include their associated custom text output.
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
//Prevent Extra 1 Hour
calc.setHours( calc.getUTCHours() +0);
//Make our result readable
var calcDate = calc.getDate()+'-'+(calc.getMonth()+1)+'-'+calc.getFullYear();
var calcTime = calc.getHours()+':'+calc.getMinutes()+':'+calc.getSeconds();
//Get How many days, months and years that has passed
var date_passed = calcDate.split("-");
var time_passed = calcTime.split(":");
if(!(date_passed.includes('1-1-1970'))) {
var days_passed = ((parseInt(date_passed[0]) - 1) != 0 ) ?
parseInt(date_passed[0]) - 1 : null;
var months_passed = ((parseInt(date_passed[1]) - 1) != 0 )?
parseInt(date_passed[1]) - 1 : null;
var years_passed = ((parseInt(date_passed[2]) - 1970) != 0) ?
parseInt(date_passed[2]) - 1970 : null;
}else{
var days_passed = null;
var months_passed = null;
var years_passed = null;
}
var hours_passed = parseInt(time_passed[0]);
var mins_passed = parseInt(time_passed[1]);
var secs_passed = parseInt(time_passed[2]);
//Set up your Custom Text output here
const s = ["sec ago", "secs ago"]; //seconds
const m = ["min", "sec ago", "mins", "secs ago"]; //minutes
const h = ["hr", "min ago", "hrs", "mins ago"]; //hours
const d = ["day", "hr ago", "days", "hrs ago"]; //days
const M = ["month", "day ago", "months", "days ago"]; //months
const y = ["year", "month ago", "years", "months ago"]; //years
var ret, retA, retB;
if (!(days_passed) && !(months_passed) && !(years_passed)
&& !(hours_passed) && !(mins_passed)) {
ret = (secs_passed == 1) ? secs_passed +' '+ s[0] : secs_passed +' '+ s[1];
}else if (!(days_passed) && !(months_passed) && !(years_passed)
&& !(hours_passed)) {
retA = (mins_passed == 1) ? mins_passed +' '+ m[0] : mins_passed +' '+ m[2];
retB = (secs_passed == 1) ? secs_passed +' '+m[1] : secs_passed +' '+m[3];
ret = retA+' '+retB;
}else if (!(days_passed) && !(months_passed) && !(years_passed)){
retA = (hours_passed == 1) ? hours_passed +' '+ h[0] : hours_passed +' '+ h[2];
retB = (mins_passed == 1) ? mins_passed +' '+ h[1] : mins_passed +' '+ h[3];
ret = retA+' '+retB;
}else if (!(years_passed) && !(months_passed)) {
retA = (days_passed == 1) ? days_passed +' '+ d[0] : days_passed +' '+ d[2];
retB = (hours_passed == 1) ? hours_passed + ' '+d[1] : hours_passed + ' '+d[3];
ret = retA+' '+retB;
}else if (!(years_passed)) {
retA = (months_passed == 1) ? months_passed +' '+ M[0] : months_passed +' '+ M[2];
retB = (days_passed == 1) ? days_passed + ' '+M[1] : days_passed + ' '+M[3];
ret = retA+' '+retB;
}else{
retA = (years_passed == 1) ? years_passed +' '+ y[0] : years_passed +' '+ y[2];
retB = (months_passed == 1) ? months_passed + ' '+y[1] : months_passed + ' '+y[3];
ret = retA+' '+retB;
}
}
- Break Down
If the month that has passed since the notification was sent, is 1, we will show the custom text for Months ( M ) at position 0 ( ie M[0] ). And this would mean 1 (month ago) not 1 (months ago) which is at position 2 ( ie M[2] ).
So the lengthy code above helps to prevent errors in counting when outputing the result to our end user.
- Lastly
Let's use a condition to check if our return contains a negative value, in this case you may have provided an invalid date.
function findNotifDate(date_notified = "2021-11-05 15:00:00") {
/**
* @ findNotifDate : Finds the Date Difference of a Notification
* @ date_notified : The notification date
**/
const date_sent_tmp = new Date(date_notified);
//Check for timestamps
if(date_notified.indexOf('-') != -1){
var date_sent = date_sent_tmp.getTime();
}else{
var date_sent = date_notified;
}
const date_now = new Date();
//current timestamp
var today = date_now.getTime();
//Subtract the timestamps
var calc = new Date(today - date_sent);
//Prevent Extra 1 Hour
calc.setHours( calc.getUTCHours() +0);
//Make our result readable
var calcDate = calc.getDate()+'-'+(calc.getMonth()+1)+'-'+calc.getFullYear();
var calcTime = calc.getHours()+':'+calc.getMinutes()+':'+calc.getSeconds();
//Get How many days, months and years that has passed
var date_passed = calcDate.split("-");
var time_passed = calcTime.split(":");
if(!(date_passed.includes('1-1-1970'))) {
var days_passed = ((parseInt(date_passed[0]) - 1) != 0 ) ?
parseInt(date_passed[0]) - 1 : null;
var months_passed = ((parseInt(date_passed[1]) - 1) != 0 )?
parseInt(date_passed[1]) - 1 : null;
var years_passed = ((parseInt(date_passed[2]) - 1970) != 0) ?
parseInt(date_passed[2]) - 1970 : null;
}else{
var days_passed = null;
var months_passed = null;
var years_passed = null;
}
var hours_passed = parseInt(time_passed[0]);
var mins_passed = parseInt(time_passed[1]);
var secs_passed = parseInt(time_passed[2]);
//Set up your Custom Text output here
const s = ["sec ago", "secs ago"]; //seconds
const m = ["min", "sec ago", "mins", "secs ago"]; //minutes
const h = ["hr", "min ago", "hrs", "mins ago"]; //hours
const d = ["day", "hr ago", "days", "hrs ago"]; //days
const M = ["month", "day ago", "months", "days ago"]; //months
const y = ["year", "month ago", "years", "months ago"]; //years
var ret, retA, retB;
if (!(days_passed) && !(months_passed) && !(years_passed)
&& !(hours_passed) && !(mins_passed)) {
ret = (secs_passed == 1) ? secs_passed +' '+ s[0] : secs_passed +' '+ s[1];
}else if (!(days_passed) && !(months_passed) && !(years_passed)
&& !(hours_passed)) {
retA = (mins_passed == 1) ? mins_passed +' '+ m[0] : mins_passed +' '+ m[2];
retB = (secs_passed == 1) ? secs_passed +' '+m[1] : secs_passed +' '+m[3];
ret = retA+' '+retB;
}else if (!(days_passed) && !(months_passed) && !(years_passed)){
retA = (hours_passed == 1) ? hours_passed +' '+ h[0] : hours_passed +' '+ h[2];
retB = (mins_passed == 1) ? mins_passed +' '+ h[1] : mins_passed +' '+ h[3];
ret = retA+' '+retB;
}else if (!(years_passed) && !(months_passed)) {
retA = (days_passed == 1) ? days_passed +' '+ d[0] : days_passed +' '+ d[2];
retB = (hours_passed == 1) ? hours_passed + ' '+d[1] : hours_passed + ' '+d[3];
ret = retA+' '+retB;
}else if (!(years_passed)) {
retA = (months_passed == 1) ? months_passed +' '+ M[0] : months_passed +' '+ M[2];
retB = (days_passed == 1) ? days_passed + ' '+M[1] : days_passed + ' '+M[3];
ret = retA+' '+retB;
}else{
retA = (years_passed == 1) ? years_passed +' '+ y[0] : years_passed +' '+ y[2];
retB = (months_passed == 1) ? months_passed + ' '+y[1] : months_passed + ' '+y[3];
ret = retA+' '+retB;
}
//Check if return contains a negative value
if(ret.includes('-')){
ret += " ( TIME ERROR )-> Invalid Date Provided!";
}
return(ret);
}
TESTING
Let's test our function shall we ?
I will use the date that I started writing this piece as the notification date.
Create a variable and call the function within the variable so that you can access its return value
var checkDate = findNotifDate("2021-11-05 15:00:00");
console.log(checkDate);
I called this function on 2021-11-06 22:21:10, passing the date 2021-11-05 15:00:00 as a parameter so that would give me 1 day, 7 hours ago
The function works just fine but you should watch out for grammatical errors too (LOL).
Since we didn't handle zero values, you should also expect to see something like 1 year 0 months ago
- What you should know
Working on this function made me to realize that Timestamps in JavaScript contain up to 13 digits while PHP Timestamps contain up to 10 digits.
To call the function, you may pass in a TIMESTAMP.
To get the timestamp for our date (2021-11-06 22:21:10), we use the getTime() method, then convert the timestamp to string using toString().
const dt = new Date("2021-11-06 22:21:10");
var ts = dt.getTime().toString(); //"1636120800000"
var checkDate = findNotifDate(ts);
console.log(checkDate);
I didn't use the JavaScript date method getYear() to find the year from the result of our calculation.
This is because, this deprecated method returns the number of years that has passed since 1900 (2021 - 1900 = 121 ) but the method getFullYear() returns the current year in full (2021).
PHP VERSION
Here's the PHP Version of this function.
Most of the concepts behind it are explained already, and the rest are self explanatory.
One thing you should note is that JavaScript automatically places time based on your browser's timezone. This is not the case in PHP.
PHP uses UTC, and for our function to work correctly, we must specify GMT according to our Timezone.
But if you had already defined a timezone for your App using date_defaut_timezone_set(), you may pass +0 as the gmt parameter.
You can learn how to set a global timezone for your App here.
I'm using GMT +1 (West African Time).
To call the function, we pass string +1 as the parameter for gmt;
$checkDate = findNotifDate("2021-11-05 15:00:00", '+1');
var_dump($checkDate);
It's still the same result! It's safe to pass in TIMESTAMP as a parameter to the function. Just make sure it's the correct timestamp or you'll get an invalid date error.
Here's the PHP VERSION
Click here to Visit my repo for the PHP Version
You can copy the code and work more on it, if you're positive that it is 100% ready to be used for production, you can drop the code repo on the comment section and I'll fork it!
Keep Coding!
Thank You!