7

I'm trying to decrement a variable once a day. I have written the following code for that.

var counter = 10; //any value

setInterval(function() {

  counter = counter - 1;

}, 86400000);

Is there a better or efficient way to achieve the same thing ?

P.S : - I do not wish to use any libraries.

Sooraj
  • 9,717
  • 9
  • 64
  • 99
  • 1
    Hmm? What library? Your current code uses none... – Jeroen Apr 28 '16 at 12:19
  • 1
    I just wanted to know if there is a better way to write this code ? In that better way, i don't want to use any libraries such as moment. That is what i meant. Sorry for the lac of clarity – Sooraj Apr 28 '16 at 12:22
  • @Jeroen he probably wants a better way to solve this problem, without using a library. He's not saying he is using one now, just that he doesn't want to in the solution :-) – Dylan Meeus Apr 28 '16 at 12:22
  • Possible duplicate: http://stackoverflow.com/questions/26306090/running-a-function-everyday-midnight – marvinhagemeister Apr 28 '16 at 12:23
  • I guess the answer in the above question is different , Please enlighten me if i'm wrong. I'm looking to do the same thing in a better way using javascript alone. – Sooraj Apr 28 '16 at 12:25
  • 4
    The issue with your current code is that it will drift after running for a few thousand years... hmph -- not good, not good. – John Weisz Apr 28 '16 at 12:28
  • Although everyone is throwing in code immediately wouldn't it be more helpfull to know a little more about the scenario? – RST Apr 28 '16 at 12:34
  • Scenario is straight forward - I have a variable. Say a count of day. I want to decrease it once every day , so that on reaching a particular count i can do some actions. – Sooraj Apr 28 '16 at 12:36

6 Answers6

2

I don't see any problem in the way you write it. You use interval, ok, but this is not the worst evil you may do to set up the variable value.

You may think of another solution with a function which returns you the current counter.

var initialValue = 20000;

function getCounter() {
  return initialValue - Math.floor(Date.now() / 1000 / 60 / 60 / 24);
}

console.log(getCounter());

The difference is that it takes the current day number starting from the UNIX time beginning. Every day the day number will be increased, so the result of the function will be decreased by 1.

But still I don't see how this solution can be better than yours.

smnbbrv
  • 23,502
  • 9
  • 78
  • 109
2

The only thing I see you miss is to set the initial value of counter variable.
I would write:

var counter = 1000; // or any useful value

setInterval(function() {
  --counter;
}, 24 * 60 * 60 * 1000); // this is more self-explanatory than 86400000, and, being evaluated just once, it will have a tiny effect on the performace of the script
MarcoS
  • 17,323
  • 24
  • 96
  • 174
0

I'm not totally sure why, but using setInterval like this makes me uncomfortable.

If I were to require this, I would use something like this approach:

var counter = 10;
var timeout = new Date();
setInterval(function(){
  if(new Date() >= timeout)
  {
    --counter; // the action to perform
    timeout = new Date(timeout.getTime() + 86400000); // update the timeout to the next time you want the action performed
  }
  console.log(counter);
},1000); // every second is probably way more frequent than necessary for this scenario but I think is a decent default in general

One thing that this allows is to, for example, set the next timeout to midnight of tomorrow rather than being locked in to "X seconds since the previous execution". The key is the inversion of control - the action itself can now dictate when it should next run.

Though I would probably abstract away the details behind an interface accepting a start, interval, and action.

ryachza
  • 4,460
  • 18
  • 28
0

Maybe use window.localStorage to save the last time, and if it is greater than 60*60*24 (seconds in a day) set the last time to this morning/now/1:00 and then decrease the value and save it.

Example:

var d = new Date();
var mins = -(1+d.getHours())*60+d.getMinutes();
var secs = mins*60+d.getSeconds(); // total seconds passed today from 1:00
var now = d.getCurrentTime():
var lastCheck = localStorage.getItem("lastCheck");
if (!lastCheck)
{
    localStorage.saveItem("lastCheck",now-secs); // beginning of today
}
var dayPassed = now - lastCheck > 24*60*60; // change to see if a day has passed
if (dayPassed)
{
    // save seconds
    localStorage.setItem("counter",localStorage.getItem("counter")-1);
    localStorage.saveItem("lastCheck",now-secs); // beginning of today
}
Tyler Dalton
  • 59
  • 1
  • 6
0

The biggest problem in my eyes is that you have to keep this one JS process running consistently for days at a time to have it do what you need. The world is not so perfect that things don't need an occasional reboot...including the average JS process.

Personally I would store a timestamp of my starting point, then (whenever I need to know how much time has elapsed) grab a new timestamp and use it to calculate how many days it has been. That way even if something interrupts my process I can still be right where I started.

BryanGrezeszak
  • 577
  • 2
  • 8
-2

It makes more sense to me to check how many days have passed since a specific date and decrement that number of days from the counter. Mostly just because I wouldn't expect anybody to leave the same page open without the need or want to reload for days on end. I would do something like this:

counter = 365; // original counter
var start = new Date(2016, 03, 20); // original date
var now = new Date();
var days = Math.floor(Math.abs(start.getTime()-now.getTime())/(24*60*60*1000))
counter -= days;

That way every time you visited the page, it would be decremented correctly. Note that this ignores any issues with leap days or time zones. The example above would have a counter of 360 for me. And then if you did expect it to be open for days, reload it automatically with:

self.setTimeout(function(){document.location.reload()}, 86400000);
jdgregson
  • 1,457
  • 17
  • 39
  • It could be a server-side javascript, not a client-side html page. – Qwertiy Apr 28 '16 at 13:07
  • `now = parseInt(d.getFullYear()+''+(d.getMonth()+1)+''+d.getDate());` - that should be wrong. – Qwertiy Apr 28 '16 at 13:14
  • What do you mean "should be"? It returns the current date as an integer, like 2016423. – jdgregson Apr 28 '16 at 13:17
  • Not sure if you know what you're doing as soon I've seen you're calling string literal inside a setTimeout... – Roko C. Buljan Apr 28 '16 at 13:39
  • I'm also not sure if you know what exactly is returned by `getMonth()` and how you plan to reliably subtract a `2016423` from any (strange) date when the month is returned as a two digit month... – Roko C. Buljan Apr 28 '16 at 13:43
  • 1. Values for 2 different dates can be equal: `d = new Date(2016,11,1); now1 = parseInt(d.getFullYear()+''+(d.getMonth()+1)+''+d.getDate()); d = new Date(2016,0,21); now2 = parseInt(d.getFullYear()+''+(d.getMonth()+1)+''+d.getDate()); now1 === now2`. 2. Even if they were not, why do you substract this strange thing? – Qwertiy Apr 28 '16 at 13:52
  • @jdgregson, `start = 2016423; now = 2016523; now-start` - is it really 100 days between these 2 dates? – Qwertiy Apr 28 '16 at 14:15
  • Oh wow, that WAS the wrong approach. Lemme fix it real quick. – jdgregson Apr 28 '16 at 14:23
  • Should be a little better. Still might not account properly for leap days though. – jdgregson Apr 28 '16 at 14:35