Im creating a simple vue.js clock, thats why im really confused why it doesn't work.
I tried to implement multiple solutions i found online, but every one of them failed to solve this problem.
App was initialized with npm init vue#latest. Im using the composition API.
Here's my js:
import {
reactive,
computed,
onMounted,
onBeforeUnmount
} from 'vue';
const data = reactive({
date: '',
time: ''
});
const today = new Date();
const getCurrentTime = () => {
const hours = today.getHours();
const minutes = today.getMinutes();
const seconds = today.getSeconds();
const zeroPadding = (num) => {
if (num < 10) {
return `0${num}`
} else {
return num;
}
};
data.time = `${zeroPadding(hours)}:${zeroPadding(minutes)}:${zeroPadding(seconds)}`;
}
onMounted(() => {
setInterval(getCurrentTime, 1000);
});
And here's the html:
<div class="time">
<time class="time__date">{{ data.date }}</time>
<time class="time__hour">{{ data.time}}</time>
</div>
I even copied this solution https://dev.to/snehalkadwe/digital-clock-using-vue-3-composition-api-5cmc, but it also isn't updating the clock. I've had enough, this is my first post on stackoverflow, so yeah, it's a big deal.
#dystrykt9 Here is the working example.
https://codesandbox.io/s/digital-clock-forked-32xmoh
The problem is today variable is constant (by constant i mean value not the const). It is set once and in the setInterval look the once set today variable each time there is same time(hour, minute and second). The reactive data.time value is same each time. But what we need is the today variable needs to get updated with latest time i.e. hour, minute and second.
I also do not get the point of data.date. May be you can use ref or single property or may be you are using that for different logic but is not present in the question code snippet.
The solution would be put the total variable in the setInterval so that every time the variable is set to latest time (hour, minute and second).
For better knowing the problem I have console.log in setInterval callback function. You can check by with setting today outside the callback and inside the callback.
Related
I would like to have a countdown timer always show a countdown for every new user. Basically, if I close the webpage, and reopen it, the timer should still be running. I'm thinking of using the JS variable code functions to define a new client's timezone together with an if statement comment and make it a repeat loop?
Basically, I would want to run a timer on the server side, not the client side.
Has anyone done this before?
Sounds something that you could try to solve with browsers localStorage. If your only requirement is to keep saved time available after you close tab/browser and come back to your page, this is a good fit for you.
Here's a small Codesandbox example code of how to conditionally check and save to localStorage and then start counter based on that value.
https://codesandbox.io/s/4xw97q02m0
EDIT: same code pasted to a post
function setCurrentTime(){
let localStore = window.localStorage.getItem("myTime") // Check if already exists
if(localStore) return localStore
const time = Date.now(); // get current time stamp
window.localStorage.setItem("myTime", time) // Save to localStorage
return time
}
function startCount(){
const time = setCurrentTime()
const elem = document.getElementById("app")
setInterval(() => {
elem.innerHTML = `seconds since time saved:
${Math.floor((Date.now() - time) / 1000)}
`
}, 1000)
}
startCount()
<div id="app"></div>
I have a React+Redux application, and I display the date in it using Moment.js. I want a function to run when the date changes.
Right now I have a function to check the date:
checkDate(local) {
if (local === null) {
localStorage.setItem('date', moment().format('MM-DD-YYYY'));
} else if (moment(local).isBefore(moment().format('MM-DD-YYYY'))) {
this.props.resetAll(); // This calls an action.
}
}
And if I call it manually, or refresh the page when the date changes, it works just fine. But, I want to be able to have my application run that this.props.resetAll() line on its own without my having to refresh the page. What would the best way be to go about it? Should it be something that happens on the Redux side of things in an action or reducer? Should I have checkDate() be called every X seconds or so somewhere in the component lifecycle (if so, where)?
Thanks in advance for any help!
I would set a timeout until 24:00 which then calls the update function:
moment() is defined as the current date/time, to get the difference to a specific time, you can use the .diff() function. So for example if you want the milliseconds till the start of the next day:
var msTillEndOfDay = moment().endOf('day').add(1, 'seconds').diff(moment(), 'milliseconds');
.endOf('day') would be 23:59:59 so you just add 1 seconds to have the next day.
You then simply set the Timeout with the specific update function or dispatch the right action:
setTimeout( () => {
this.props.dispatch({type: 'UPDATE_DATE'})
}, msTillEndOfDay);
In my app, I use this code to listen only to the children added after the current time:
var start = new Date().getTime();
firebase.database().ref(path).orderByChild('created').startAt(start).on('child_added', function(value){
console.log(value.val());
});
In the browser, this method works well. I see the child only if I start to add it after the current time.
In the smartphone, this method doesn't work. It works only if I start to add a children after a certain amount of seconds. I think that this happens because the current time of the smartphone is different with the current time of the server.
Is there any way to fix this without having to take the last element?
If the clock on your phone is off, this will not work reliably.
Firebase detects the offset of the local clock to the server time and exposes this in a value .info/serverTimeOffset. You can use this to correct for the clock skew as explained in the documentation on clock skew:
var offsetRef = firebase.database().ref(".info/serverTimeOffset");
offsetRef.on("value", function(snap) {
var offset = snap.val();
var estimatedServerTimeMs = new Date().getTime() + offset;
});
Read the linked documentation for a full explanation.
EDIT: I think I should make things more obvious.
What I am trying to do is to make the function that displays the "time ago" from the submitted date of the post auto refresh every minute so that it stays relatively accurate even if the template is not re rendered.
I'd like to auto update my timeago value in my template but it is not working.
I've tried to set up my code with a reactive function, based on the answer to a similar question (https://stackoverflow.com/a/17933506)
Here's my code:
var timeAgoDep = new Deps.Dependency(); // !!!
var timeAgo;
var timeAgoInterval;
Template.postItem.created = function() {
function getTimeago() {
//var now = new Date();
timeAgo = moment(this.submitted).twitter();
timeAgoDep.changed(); // !!!
};
getTimeago(); /* Call it once so that we'll have an initial value */
timeAgoInterval = Meteor.setInterval(getTimeago, 5000);
};
Template.postItem.posted = function() {
timeAgoDep.depend(); // !!!
return timeAgo;
};
Template.postItem.destroyed = function() {
Meteor.clearInterval(timeAgoInterval);
};
I'm pretty sure that the problem comes from this.submitted because if I assign timeAgo = now for example, it will display the time and update like it's supposed to.
I also know that moment(this.submitted).twitter() works fine because when all I do is return it through a helper, it works.
A much better way to do this is to just embrace Meteor's reactivity and render time-dependent values reactively. In your case, the problem is that you are invalidating the dependency once every 5 seconds for each postItem rendered, which will quickly turn into a huge mess.
See https://github.com/mizzao/meteor-timesync for a package that provides reactive time variables on the client (and they are synced to server time too!) It's basically doing what you want, but in a cleaner way. (Disclaimer: I wrote this package.)
You can use moment in the same way to compute the actual string to display. For example, get rid of all the other stuff and just use
Template.postItem.posted = function() {
return moment(this.submitted).from(TimeSync.serverTime());
}
The moment().twitter() extension doesn't seem like a good choice because it only uses the current client time and doesn't allow you to pass in a specific (i.e. server-synced) time or reactive value.
I was creating a countdown timer using javascript; I can use jQuery. I want the global time not the PC time.
How could I get the global time using javascript or the jQuery?
Use a time API like: http://www.timeapi.org/
<script type="text/javascript">
function myCallback(json) {
alert(new Date(json.dateString));
}
</script>
<script type="text/javascript" src="http://timeapi.org/utc/now.json?callback=myCallback"></script>
You can use the UTC methods from Date object: http://www.w3schools.com/jsref/jsref_obj_date.asp
var utcDate = new Date(json.dateString);
alert(utcDate.getUTCFullYear() + '-' + utcDate.getUTCMonth() + utcDAte.getUTCDate());
Well unless you make a request to some service that publishes like the current time of an atomic clock or something, you'll have to rely on your computers local time. As JS inherently relies on your local system.
The Date object has built-in methods for getting UTC values. Instead of myDate.getHours() use myDate.getUTCHours(), etc.
See the MDN reference for JavaScript date methods.
Using your current API with server time like following:
res.send(new Date());
You can get an approximate clock difference time with following:
// Get current local time before request
const initialLocalTime = new Date().getTime();
// Request server time
const response = await fetch('/api/time');
const data = await response.json();
const serverTime = new Date(data);
// Get current local time after request
const finalLocalTime = new Date().getTime();
// Calculate the request time
const dateDiff = finalLocalTime - initialLocalTime;
// Apply the request time to server time
serverTime.setTime(serverTime.getTime() + dateDiff);
// Calculate the time difference
const diff = serverTime.getTime() - finalLocalTime;
// Return the final difference time
return diff;
And, you can use the diff value in your page:
const now = new Date()
now.setTime(now.getTime() + diff);
console.info('Current time:', now);