where should timezone processing be done, on server or on client? - javascript

Where do you process timezone calculations, is it better do do it on the server or on the client using a javascript library like moment?
Currently I am doing it on server using this library:
https://github.com/camroncade/timezone
and these two:
public function getPublishedAtAttribute()
{
if(Auth::guest()) {
return $this->attributes['published_at']->format('Y-m-d\TH:i\Z');
}
else {
$timezone = Auth::user()->timezone;
if(isset($this->attributes['published_at']))
return Timezone::convertFromUTC($this->attributes['published_at'], $timezone, 'Y-m-d H:i');
else
return null;
}
}
public function setPublishedAtAttribute($published_at)
{
if($published_at) {
$published_at_temp = new Carbon($published_at, Auth::user()->timezone);
$this->attributes['published_at'] = Timezone::convertToUTC($published_at_temp->addSeconds(59), Auth::user()->timezone);
}
elseif(!$this->published_at) {
$this->attributes['published_at'] = Carbon::now();
}
}
Are there any minuses for doing it on the server or any pluses doing it on the client?
Which is better approach?

Store always server time. It is easy to deal with, so you can give an easy opportunity to change timezone (just change one field, not all existing records).
Then convert every time output in view . Create simple timeHelper which is aware of current user and his timezone and inject it in view #inject('timehelper', 'App\Services\Timehelper') and {{ $timehelper->out($model->created_at) }}. In out() just apply user's timezone. Sometimes it is easy to output raw time with server timezone and then convert it via moment.js, using some attribute: <span ts="150...">20:20 20th July</span>
You have to store client's time just in cases like when you have strict billing, based on users' local time.

On the client, you have to account for a user taking their laptop with them when they travel to a different timezone. Now there's the server time, the user's local time, and the user's laptop time. And that's before you factor in any latency in a time-sensitive transaction.

Do it on server side. I think it would be more "beautiful"

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

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.

How do I get user's local date and time in RESTful app with Spring MVC

I have a app where the user is able to perform actions, but only once and if his local time is before noon. The question is how can I retrieve this from user?
Say I have a method in the controller like this:
#PostMapping(value = "/performaction")
public void performIt()
{
if(/*somehow getHour()*/ < 12)
{
perform();
}
else reject();
}
I know that JS can help out, by calling var date = new Date() I can retrieve it, but I don't have any JSP pages to put this code and get locals. The service is completely REST with plain text. How can I do that?
you can use java8's LocalTime.now() and do compare like this
LocalTime currentTime = LocalTime.now();
LocalTime noon= LocalTime.of(12, 0);
if(currentTime.isBefore(noon){
}
Get the time stamp from the server itself if you can ignore the network time in your use-case.

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