Calculate difference between two timestamps - node.js

I'm using the twitch api and TMI.JS
I'm trying to fetch the timestamp of followed_at. The timestamp I got was 2021-12-25T15:49:57Z, how would I go about getting the current timestamp, and then calculating the difference. So in this instance it would return followername has been following streamername for 20 days 19 hours (at the time of writing it's been 20 days and 19 hours since the followed_at timestamp.)
if (message.toLowerCase() === '!followage') {
client.say(channel, `#${tags.username}, does not work yet `)
console.log(`${channel.id}`)
console.log(`${tags['user-id']}`)
async function getData() {
const res = await fetch(`https://api.twitch.tv/helix/users/follows?to_id=226395001&from_id=${tags['user-id']}`, { method: 'get', headers: {
'Client-Id': 'cut out for a reason',
'Authorization': 'Bearer cut out for a reason'
}});
const data = await res.json();
console.log(data)
if (data.data[0]) {
client.say(channel, `#${tags.username}, followed at ${data.data[0].followed_at}`)
} else {
client.say(channel, `You aren't followed!`)
}
}
getData()
}
Above is my code for fetching it, and then sending it to the channel.

Here's how you can do it:
const followedAt = new Date('2021-12-25T15:49:57Z');
const currentDate = new Date();
const diffTime = Math.abs(currentDate - followedAt);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
console.log(diffTime + " milliseconds");
console.log(diffDays + " days");
And that's the way to get days and hours:
const followedAt = new Date('2021-12-25T15:49:57Z');
const currentDate = new Date();
const diffTime = Math.abs(currentDate - followedAt);
const diffTotalHours = Math.floor(diffTime / (1000 * 60 * 60));
const diffDays = Math.floor(diffTotalHours / 24);
const diffHoursWithoutDays = diffTotalHours % 24;
console.log(`${diffDays} days and ${diffHoursWithoutDays} hours`);

Related

Run Nodejs App Every 6 Hours with Aysnc Await

I want to run a Script every 6 Hours
const { IgApiClient } = require("instagram-private-api")
const ig = new IgApiClient()
const USERNAME = "abc"
const PASSWORD = "xyz"
ig.state.generateDevice(USERNAME)
const main = async () => {
var birthday = new Date(2069, 05, 14);
var today = new Date();
birthday.setFullYear(today.getFullYear());
if (today > birthday) {
birthday.setFullYear(today.getFullYear() + 1);
}
var daystill = Math.floor((birthday - today) / (1000*60*60*24))
await ig.simulate.preLoginFlow()
await ig.account.login(USERNAME, PASSWORD)
process.nextTick(async () => await ig.simulate.postLoginFlow())
await ig.account.setBiography(`${daystill} Days till my Birthday, Today is ${new Date().getDate()}/${new Date().getMonth()}/${new Date().getFullYear()}. (AutoGenerated)`)
}
main()
instagram-private-api
About Script: update my Instagram Bio with Async Await
Problem / Goal:
I Tried using node-cron, but It returns some Error (I think Async is causing the Problem), I also tried while loops and setInterval()s
I want this Script/File to run every 6 Hours, I have a heroku account (if that helps)
Error when i use node-cron:
node:internal/process/promises:288
triggerUncaughtException(err, true /* fromPromise */);
Code for node-cron:
cron.schedule('* * * * *', () => { // this is not every 6hrs
const main = async () => {
//same as above
}
main()
})
Doing it the async await way as the title says.
// used to measure time
import { performance } from 'perf_hooks';
const interval = 1000; // in ms
(async function main(){
let start_time = performance.now();
// do stuff
let stop_time = performance.now();
let timeout = interval - (stop_time - start_time);
setTimeout(main, timeout);
})();
edit:
To explain the syntax behind the main function.
()(); will automatically call the function inside of first braces on script start.

Delete Firebase document after 30 minutes

I want to delete some documents in Firebase 30 minutes after creation. I'm trying to use Firebase Functions for this. Somehow it always deletes documents without checking the dates. Here is my code. It's working but I don't understand why can't I check the dates.
exports.scheduledFunction = functions.pubsub.schedule('every 1 minutes').onRun((context) => {
const now = new Date();
const queryTime = new Date(now - 30 * 60000);
const trips = admin.firestore().collection('trips');
const allTrips = trips.get().then(snapshot => {
snapshot.forEach(trip => {
if (trip.data().date < queryTime) {
admin.firestore().collection('trips').doc(trip.id).delete();
}
});
});
return allTrips;
});
The variable now is a Date and not a number. Try using Date.now() to get current timestamp instead:
const queryTime = new Date(Date.now() - 30 * 60000);
Then you can use where() clause to get documents where date field is older than 30 minutes instead of fetching all documents and filtering them out yourself. This will save many read charges as you are fetching matched documents only and not the whole collection.
export const scheduledFunction = functions.pubsub
.schedule("every 1 minutes")
.onRun(async (context) => {
// async fn ^^
const queryTime = new Date(Date.now() - 30 * 60 * 1000);
// Alternatively:
// const queryTime = admin.firestore.Timestamp.fromMillis(Date.now() - 30 * 60 * 1000);
// Query to fetch documents where date is less than queryTime
const tripsQuery = admin
.firestore()
.collection("trips")
.where("date", "<", queryTime);
const allTrips = await tripsQuery.get();
// Mapping an array of delete promises
await Promise.all(allTrips.docs.map((d) => d.ref.delete()));
return allTrips;
});
Alternatively you can also use batched writes to delete up to 500 documents at once.

How to convert seconds into human readable time lapse

I have this function
const performance = require('perf_hooks');
var t0 = performance.now();
setInterval(printStatus, 20000);
function printStatus() {
console.log(
`Total records: ${count}`
);
console.log("Time elapsed" + (performance.now() - t0)/60000 + "minutes")
}
This prints minutes like this:
Time elapsed0.3334145895500978minutes
I want it to become human readable HH:MM:S
How do I make it happen?
I would do this:
const performance = require('perf_hooks');
var t0 = performance.now();
setInterval(printStatus, 20000);
function printStatus() {
console.log(
`Total records: ${count}`
);
const msElapsed = (performance.now() - t0);
const hhmmss = (new Date(msElapsed)).toISOString().substr(11,8);
console.log("Time elapsed " + hhmmss )
}

MongoDB aggregation returns empty array with NodeJS

I want to create a script which is taking the average of the Volume for last 7(for example) days.
I'm stuck with aggregation stages since first stage I need to take Date for last 7 days and in second stage calculate Average of Volume
Package list:
Node-schedule - */1 * * * * (Runs the script every minute)
Binance API - Taking data from them.
Screenshot for showcasing how the document looks like in MongoDB.
Aggregation part of the Code.
const average = await dbo.collection(symbol).aggregate([{
'$match': {
'Date': { '$gte': new Date((new Date().getTime() - (7 * 24 * 60 * 60 * 1000))) }
},
},
{
'$group': {
_id: null,
'Volume': { '$avg': '$Volume' }
},
}
]).toArray();
This code returns me an empty array in terminal like this > []
Full Code here.
const { MongoClient } = require('mongodb');
const schedule = require('node-schedule');
const fetch = require("node-fetch");
const symbols = ["ADABTC", "AEBTC", "AIONBTC", "ALGOBTC", "ARDRBTC"];
//a descriptive name helps your future self and others understand code easier
const getBTCData = async symbol => { //make this function accept the current symbol
//async/await lets us write this much nicer and with less nested indents
let data = await fetch(`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=30m&limit=1`).then(res => res.json());
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Volume: parseFloat(d[5]),
Timespan: 30,
}
});
console.log(btcusdtdata);
saveToDatebase(symbol, btcusdtdata);
//recursive functions are complicated, we can get rid of it here
//by moving the responsibility to the caller
};
//helper function for an awaitable timeout
const sleep = ms => new Promise(res => setTimeout(res, ms));
const j = schedule.scheduleJob('*/1 * * * *', async() => {
//expand this function to be responsible for looping the data
for (let symbol of symbols) {
//we can pass symbol to getBTCData instead of making it
//responsible for figuring out which symbol it should get
await getBTCData(symbol);
await sleep(8000);
}
});
//make this a helper function so `saveToDatabase()` isn't also responsible for it
const getDateTime = () => {
let today = new Date();
let date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
let time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
return date + ' ' + time;
};
const saveToDatebase = async(symbol, BTCdata) => {
try {
const url = 'mongodb://username:password#ipadress:port/dbname';
let dateTime = getDateTime();
let db = await MongoClient.connect(url, { useUnifiedTopology: true });
const dbo = db.db('Crypto');
const myobj = Object.assign({ Name: symbol, Date: dateTime }, BTCdata[0]);
await dbo.collection(symbol).insertOne(myobj);
const average = await dbo.collection(symbol).aggregate([{
'$match': {
'Date': { '$gte': new Date((new Date().getTime() - (7 * 24 * 60 * 60 * 1000))) }
},
},
{
'$group': {
_id: null,
'Volume': { '$avg': '$Volume' }
},
}
]).toArray();
console.log('1 document inserted');
console.log(average);
db.close();
} catch (e) {
console.error(e)
}
};
EDIT1
If I delete $match part my script is working and I receive average of Volume.
Screenshot of terminal after success try without $match
EDIT2
According to the last answer I understand that I need to change Date format from string to object, but I really can't get how I can do it in this part?
const getDateTime = () => {
let today = new Date();
let date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
let time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
return date + ' ' + time;
};
EDIT3
After editing the Date format I receive a Document in MongoDB in strange Date format like - Date:2020-07-20T13:24:02.390+00:00
Code here:
const getDateTime = () => {
let today = new Date();
let date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
let time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
return new Date();
};
The problem is on the Date field format.
The getDateTime function returns a string so Mongo is managing the field as a string not as a Date object so the $gte check will compare string not dates.
You should change the function to getDateTime = () => new Date(). Mongo will manage the date correctly storing in UTF Timezone.
Tring to query a date-string in the $match field would be really difficult.
Edit:
To update the typing just:
const getDateTime = () => {
return new Date();
};

setTimeout() function is not executed properly

I have to send an SMS 15 minutes before the appointment is there. I have written the code, but it is called at the time of execution itself. Is there any other method or how do I solve this?
"RP.remindePatient" is the function that has to be called 15 minutes before the appointment time.
sendApptConf(s) {
var number = Phone;
var msg = urlencode("Hello " );
var smsData = 'username=' + username + '&hash=' + hash + '&sender=' + sender + '&numbers=' + number + '&message=' + msg;
var options = {
host: 'api.textlocal.in',
path: '/send?' + smsData
};
var callback;
console.log(options);
callback = function (response) {
var str = '';
// Another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
console.log("new Data received")
str += chunk;
console.log(str);
});
// The whole response has been received, so we just print it out here.
response.on('end', function () {
console.log(str);
});
}
http.request(options, callback).end();
// Send SMS using Textlocal DONE
const convertTime = consultDate + ' ' + consultTime;
var d = new Date(convertTime);
var ms = d.getTime();
var milliLess15 = ms - (15 * 60 * 1000);
console.log(milliLess15);
setTimeout(function () {
console.log("I should be called after some delay")
RP.remindePatient(userPhone, patientName, drName, consultMode, consultDate, consultTime, transId, email, paymentDetails);
}, milliLess15);
I think there is a small issue in your logic. As you would already know, setTimeout(function () {}, milliseconds) will fork the function() after milliseconds you have specified.
Now let's focus on the below snippet of code:
const convertTime = consultDate + ' ' + consultTime;
var d = new Date(convertTime);
var ms = d.getTime();
var milliLess15 = ms - (15 * 60 * 1000);
Let's say your appointment is at 12:00 pm today (in millisec let's say 1492776423) and current execution time is 10:00 am (in millisec 1485576423). By your logic, you are calling the function() after: var milliLess15 = ms - (15 * 60 * 1000) which is 1492776423 - (15 * 60 * 1000) = 1491876423. Note here that, you don't want to call function() after 1491876423 millisec. Rather you want to call it after millisec equivalent of 12:00 - 10:00 - 00:15. So your logic should look something like:
const convertTime = consultDate + ' ' + consultTime;
var d = new Date(convertTime);
var ms = d.getTime();
var currentTime = new Date();
var currentTimeMilli = currentTime.getTime();
var milliLess15 = ms - (15 * 60 * 1000) - currentTimeMilli;
Rest of the code will remain the same. Hope this answer helps you!
Don't call the variable after timeout. Just put in:
setTimeout(function () {
console.log("I should be called after some delay")
RP.remindePatient(userPhone, patientName, drName, consultMode, consultDate, consultTime, transId, email, paymentDetails);
}, 900000);

Resources