Timestamps for messages - javascript

I'm using firebase's database to host a real time messaging web app. I've finished the basic implementation but now want to add timestamps for users to see when messages were sent.
To add a message to a chatroom I use firebase.push() with the value as the sent message. I guess I'll have to switch this to .update() with the value as an object with the fields message and time sent.
I'm trying to figure out how to populate this time sent. I've heard of firebase.database.ServerValue.TIMESTAMP but from what I can tell it's hard to change that into a date and time. I'm heavily considering a unix timestamp like this var unix = Math.round(+new Date()/1000); since this is easy to convert.
Does anybody with any experience have any tips for which direction I should take? I don't need the timestamp to be super precise, just the date, hour, and minute.

When you write firebase.database.ServerValue.TIMESTAMP to a node, the value becomes a UNIX timestamp. See the Firebase reference documentation for an example how to write this:
var sessionsRef = firebase.database().ref('sessions');
var mySessionRef = sessionsRef.push();
mySessionRef.update({ startedAt: firebase.database.ServerValue.TIMESTAMP });
When you read this value, you can convert it back into a Date object with:
sessionsRef.on('child_added', function(snapshot) {
var startedAt = new Date(snapshot.val().startedAt);
});

Related

firebase timestamps not serverside created

I have a chat app in react native using firebase and it is crucial to me that the timestamps are all synchronised and created serversided, not from the client. Clients can have different times depending on the settings on the mobile phone.
I tried out following function to prove my point:
const comparetimes = async () => {
const timezone1 = firebase.firestore.Timestamp.now();
const timezone2 = (firebase.firestore.Timestamp.now()).toMillis();
const timezone3 = Date.now();
console.log(timezone1);
console.log(timezone2);
console.log(timezone3)
}
What shocked me is the result of this function:
{"nanoseconds": 79000000, "seconds": 1641054839}
1641054839080
1641054839080
Apperently the firebase timestamp is the exact same as Date.now() which is a direct timestamp taken from the mobile phone, and therefore unaccurate.
What can I do to have timestamps not created by the client but by the server, in this example firebase? Do I need to checkout some APIs or is there something I miss here?
When you call Timestamp.now(), it really is just taking the timestamp on the client device. That's expected.
Read the documentation on how to use server timestamps. You must use the token value returned by firestore.FieldValue.serverTimestamp() in order to tell Firestore to use the current moment in time as the request reaches the server.
When storing timestamps, it is recommended you use the serverTimestamp
static method on the FieldValue class. When written to the database,
the Firebase servers will write a new timestamp based on their time,
rather than the clients. This helps resolve any data consistency
issues with different client timezones:
firestore().doc('users/ABC').update({
createdAt: firestore.FieldValue.serverTimestamp(),
});
Also read:
https://medium.com/firebase-developers/the-secrets-of-firestore-fieldvalue-servertimestamp-revealed-29dd7a38a82b

How to get current timestamp with Firebase react native?

Alright I've followed this question verbatim Firebase TIMESTAMP to date and Time and am posting to my Firebase database like this:
function storeUserInfo(username, industry, role, color) {
if (username != null && industry != null && role != null && color != null) { //use for errors later
let timestamp = firebase.firestore.FieldValue.serverTimestamp();
let push = firebase.database().ref('users').push();
push.set({
name: username,
industry: industry,
role: role,
color: color,
date: new Date(timestamp.toDate()).toUTCString()
});
}
}
This gives me the error: timestamp.toDate() is not a function
Ive tried several other methods like Firebase.ServerValue.TIMESTAMP but need to get the current formatted date for Firebase database. How can I do this?
You have a couple of things going wrong here. Firstly, you're trying to write to Realtime Database (via firebase.database()), but you're trying to use Firestore's timetamp with it. Firestore and Realtime Database are different databases with different APIs. A Firestore timestamp would not be helpful to you here.
If you want to get a date as reckoned by the client machine's clock, simply call new Date() with no arguments.
push.set({
name: username,
industry: industry,
role: role,
color: color,
date: new Date().toUTCString()
});
I suggest actually just storing an integer instead of a formatted string - it will probably be easier for you in the long term.
If you want to write an integer value based on the database server's sense of time, you would do this instead, using ServerValue.TIMESTAMP, which gets an actual integer value as soon as the write hits the server:
date: firebase.database.ServerValue.TIMESTAMP
If you were actually just hoping to get a server timestamp from Firestore's Timestamp API, that's not possible, because the server timestamp can only be calculated on the server. The error is telling you that there is no toDate() method available on the FieldValue type object returned by FieldValue.serverTimestamp(). It doesn't return a Timestamp. It returns a token that you can provide to Firestore that interprets the timestamp on the server and not in the client app. You should provide this token directly to Firestore if you want the server's timestamp in that field:

Show same content at same time in different browser

I am developing a numbers game where users will buy numbers and after 2 days winners will be drawn.
I am using PHP for the backend and jQuery for the frontend.
My problem is when drawing occurred user on different browser can't see same numbers, these draw numbers are being generated by PHP.
I was thinking maybe I can build these game by PHP and Javascript but it looks not easy. Can you guys please suggest some alternative? How can I improve this code to show the same number on the different browser?
I have the idea that it is not possible to generate a random number for each request. Maybe I can save the number in the database and then get this number in PHP such that the number will be unique for each request.
The actual issue is to create the same content for each user in different browsers. Any help would be really appreciated.
Javascript:
var myTimer = setInterval(checkDrawDate, 1000);
function checkDrawDate() {
var today = new Date();
var date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = date+' '+time;
var x = new Date(dateTime);
var y = new Date("{{$drawDate}}"); //this is laravel variable which contain drawdate e.g. 2017-07-05
if(x >= y){
drawNumber();
}
}
function drawNumber(){
$.get("{{ route('ajaxcomparepowerball') }}",{'gameId': gameid}, function(res){
$('#mybets').html(res.html);
});
}
PHP:
public function ajaxDrawNumber(Request $req){
return rand(0,49);
}
A Cron Job will be needed to implement this functionality. As you are drawing a number on particular time (after $drawDate in your case). So the cron job will execute once in day, check whether $drawDate for each game is today or passed. If condition true, $drawDate <= now, call a function to generate random draw number rand(0,49) and save it to database corresponding to gameid of matched games(having $drawDate <= now).
By doing this, a lot Javascript work will be reduced. In JS, then need to hit an ajax request with gameid to fetch record having draw number for particular game from database. If record not found, it means random number not drawn yet.
I think you are using Laravel, so to schedule tasks in laravel visit here.
Here some possible solutions.
If you need the same data modified for users in real time I think the best option is WebRTC, quick start here. And here a simple example sending strings in real time between clients.
If you also need interaction server to client you could use server-sent events.
You could perform a bidirectional communication between browser and a server using WebSockets. You can send and receive event-driven responses. Using a database you could communicate two clients.
The easiest is using a database to store the information and perform ajax to send data to the server (and database) and server-sent events to send data to the clients.
Basic Server-sent event example:
Javacript:
var evtSource = new EventSource("myserver.php");
evtSource.onmessage = function(e) {
// listening for new messages here
alert(e.data)// e.data is mynumber
}
Php (myserver.php)
<?php
header('Cache-Control: no-cache');
header("Content-Type: text/event-stream\n\n");
while (1) {
//perform a query in your database with your driver
$result = mysql_query("SELECT mynumber FROM mytable WHERE user = 1");
$row = mysql_fetch_assoc($result);
echo $row['mynumber'];//<-- sending mynumber to client
ob_end_flush();
flush();
sleep(1);// <-- this is every second, but you could fire this with ajax or some other event.
}
This code send a number from server to a client that is listening. If a user made a change, one possibility is that client send an ajax to update some value in the database. So, at the same time, the ajax server could send this as an update to clients listening. In that way the whole process is completed.
I think all you need is this. Call a function in every, say 5 seconds or less and fetch data from server and update it in the page.
window.setInterval(function(){
updateNumber();
}, 5000);// set for every five seconds
function updateNumber(){
//ajax code to fetch live data and append the data in the numbers container
}
And dont forget to cross check the data before saving the numbers in the server.
Hope it helps.!!!
To save and maintain users state, key value store like Aerospike can be used. It is very easy to save and retrieve data in key value store. In above case we just have to generate a unique key using gameId, userId and date. And save user's data against the unique key.
To get started with Aerospike php client following is Aerospike php client
If data is present against the unique id for that particular user just return it, else create the new random number save it against the unique key and return it. Please be careful while creating unique key. Instead of using server side date-time please send date in ajax call request so there will not be any issue with time zone. It will be always user's timezone and there will not be any issue if server is in different timezone and user is in different timezone.
function drawNumber(){
$.get("{{ route('ajaxcomparepowerball') }}",{'gameId': gameid,'date':user-timezone-date}, function(res){
$('#mybets').html(res.html);
});
}
Here "user-timezone-date" should be fix date format like 'MM-dd-yy' which will indicate the same day. hours or seconds should not be included while generating unique key otherwise at the time of retrieving the user's state; generating particular unique will be changed every hour or every second and whole purpose of of doing this will be shattered.
I am new to StackOverFlow so I am not able to comment on the answers. In case of corn job as well we have to be careful with time-zones if server and users are in different time zones. Otherwise user's will see different random number before user's day is complete. Please improve answer by commenting on it and suggestions are always welcome.

Delay a message in the Service Bus Queue from being processed until a scheduled time with NodeJS

so far I have tried many different tutorials to get this to work but so far I have not been able to achieve this.
Currently I have a nodejs app that sends messages to the Service Bus Queue and another nodejs that polls continuously. My goal is to send a message to the queue with a specific time and date on which the polling system can process the message.
My results so far is that as soon as I send the message, it becomes visible and it is processed right away, here is what I have
//made some changes after the first suggestion, but still does not work
//what I'm doing here is offsetting the time difference with UTC(im in GMT-7 tz) by adding it manually
//(this is just a test so if this would have worked I would have made it more elegant)
var scheduled_time = new Date().valueOf() + ((60000*60)*7.5);
var current_time = Date.now();
console.log(scheduled_time, current_time);
var message = {
body: 'Time ' + current_time.toString(),
brokerProperties:{
ScheduledEnqueueTimeUtc: scheduled_time,
TimeToLive: 8
},
customProperties: {
testproperty: 'TestValue'
}};
serviceBus.sendQueueMessage('myqueue', message, function(error){
if(!error){
// message sent
console.log('message sent');
}
});
My receiver is very simple
function receiveMessages() {
serviceBus.receiveQueueMessage(queue,
function (error, message) {
if (error) {
console.log(error);
} else {
console.log('Process after ' + message.brokerProperties.ScheduledEnqueueTimeUtc);
}
});
};
so far I have read the GitHub page with the description of the properties of the message and it seems correct to what I have but it still does not work.
Thank you
Date.now() returns a date in your timezone, not in UTC. You need to convert it to UTC. This question can help you with that.
It appears one of the problems is with the format of ScheduledEnqueueTimeUtc. I was able to successfully delay queue messages in Azure Service Bus from Node.js using moment.js to adjust and format the date:
// Delay message by 1 hour
var scheduled_time = moment().utc().add(1, 'hour').format('M/D/YYYY H:mm:ss A');
var message = {
body: 'Time ' + Date.now().toString(),
brokerProperties: {
ScheduledEnqueueTimeUtc: scheduled_time
},
customProperties: {
testproperty: 'TestValue'
}
};
The Service Bus docs and JavaScript SDK unfortunately don't appear to mention anything about what format ScheduledEnqueueTimeUtc should be in other than that the type is a String. However, if you look at code examples in .NET languages, the value is being passed using DateTime.toString() which defaults to the 'G' general date and time format specifier (example: 5/1/2009 9:00:00 AM). Following these examples, we can duplicate the format using something like moment.js: "M/D/YYYY H:mm:ss A". As TheDude mentioned, bear in mind the value must be in UTC and not local time.
Also, your TimeToLive value of 8 may be too short to allow processing, and note that delaying or scheduling a queue using ScheduledEnqueueTimeUtc doesn't guarantee that it will be processed at the specified date and time. It only guarantees the message won't be processed beforehand. See remarks in https://msdn.microsoft.com/en-us/library/microsoft.servicebus.messaging.brokeredmessage.scheduledenqueuetimeutc.aspx
Per my experience, I think you could try to check the region for the Service Bus and your Node.js Application on Azure for keeping the same regions.
More information, please refer to the broker properties for BrokeredMessage Class https://msdn.microsoft.com/en-us/library/azure/microsoft.servicebus.messaging.brokeredmessage.aspx.
The above example uses the azure-sb package which in turn uses HTTP to talk to Azure Service Bus. The newer #azure/service-bus package uses AMQP and is more performant than the azure-sb.
If using the #azure/service-bus package, then you can set the scheduledenqueuetimeutc directly on the message and send it. This property is of type Date

Are Javascript date/time functions dependent on the client machine?

I was wondering if Javascript date/time functions will always return correct, universal dates/times
or whether, Javascript being a client-side language, they are dependent on what the client machine has its date set to.
If it is dependent on the client machine, what is the best way to get the correct universal time?
Javascript only knows as much about the correct time as the environment it is currently running within, and Javascript is client-side.
So, Javascript is at the mercy of the user having the correct time, AND timezone, settings on the PC on which they are browsing.
If the user has the incorrect time zone, but correct time, then functions depending on time zones like getUTCDate() will be incorrect.
If the user has the incorrect time, then all time-related functions in Javascript will be incorrect.
One could make the argument, however, that if the user wanted correct times on their PC they would have set the correct time. The counter to that is that the user may not know how to do that.
Edit Jun 2020: It is common now for operating systems to update the computer's system time automatically from a time server, significantly reducing the chances of incorrect time on the client. There is still a possibility of an incorrect time zone, but this too is often geo-detected somehow by systems during installation and/or is tied to the user's supplied country of residence in their relevant online account.
As thomasrutter has said javascript date functions are reliant on the client's machine. However if you want to get an authoritative date you could make and ajax request to your server that just returns the date string. You can then convert the date string into a date object with the following
var ds = ... // Some ajax call
var d = new Date(ds);
or whether, Javascript being a client-side language, they are dependent on what the client machine has its date set to.
Yes, this is correct.
If it is dependent on the client machine, what is the best way to get the correct universal time?
To get the time/date from an authoritative source, not from a client machine.
The methods do what they're documented to do. The best way to get UTC info is obviously to use the UTC methods:
getUTCFullYear(), getUTCMonth(), getUTCDate(), etc.
Javascript's date() constructor will always get the time of local machine.
The best way to get the universal time are
1) get the time from your server by an ajax call. This method will always show your server time no matter where your user is.
2) Get the time from an third party server. Use a third party server to get time from any time zone / country of the world. Here I'm explaining this method by using plain javascript and axios. The service I'm using is worldtimeapi.org/
VANILLA JS
function getTime(url) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.open("GET", url);
req.onload = () =>
req.status === 200
? resolve(req.response)
: reject(Error(req.statusText));
req.onerror = (e) => reject(Error(`Network Error: ${e}`));
req.send();
});
}
Now Use this function to make the ajax call
let url = "http://worldtimeapi.org/api/timezone/Etc/GMT";
getTime(url)
.then((response) => {
let dateObj = JSON.parse(response);
let dateTime = dateObj.datetime;
console.log(dateObj);
console.log(dateTime);
})
.catch((err) => {
console.log(err);
});
AXIOS
axios({
url:"http://worldtimeapi.org/api/timezone/Etc/GMT",
method: "get",
})
.then((response) => {
let dateObj = response.data;
let dateTime = dateObj.datetime;
console.log(dateObj);
console.log(dateTime);
})
.catch((err) => {
console.log(err);
});
Hope that helps. Bear one thing in mind though, worldtimeapi.org/ is a third party service. If they choose to terminate their service, your code will break. Happy coding.

Categories

Resources