0

Here on stackoverflow I found a very nice and simple way to calculate a date in the past with timestamps using the modulo:

var timestampNow = moment().valueOf(); //get timestamp in miliseconds of current date and time
var interval1H = 60 * 60 * 1000; //this is 1 hour in miliseconds
var timestampMinus3Days = timestampNow - (timestampNow % (interval1H*24*3)); //substracts the modulo from current timestamp
alert("Calculated time: " + moment(timestampMinus3Days).format("DD.MM.YYYY HH.mm.ss"))

But the variable timestampMinus3Days does not give me the date 3 days before. Currently, at this moment I am writing the post, it gives me Monday 20th of April 00:00 AM.

I am 100% sure this worked before with other dates. But it seems the modulo calculation does not work, maybe with this certain date.

Has anyone an explanation, and how to improve the code?

flo
  • 559
  • 1
  • 8
  • 26
  • 2
    Just... `timestampMinus3Days = timestampNow - 3 * 24 * 60 * 60 * 1000;` – Niet the Dark Absol Apr 21 '20 at 05:17
  • Since you're uising moment.js, use it: `moment().subtract(3, 'days').format('DD.MM.YYYY HH.mm.ss')`. Adding or subtracting milliseconds is not a good idea as days are not always 24 hours long where daylight saving is observed. If you also want it at the start of the day, then include `.startOf('day')`. – RobG Apr 21 '20 at 22:40

2 Answers2

2

Can you change it to just

var timestampMinus3Days = timestampNow - (interval1H*24*3);
ledlogic
  • 774
  • 1
  • 9
  • 19
  • Code–only answers aren't particularly helpful. This doesn't work accurately over daylight saving boundaries as not all days are 24 hours long. So sometimes it will subtract slightly less than 3 days, other times slightly more. It also doesn't explain why the OP's code doesn't work. – RobG Apr 22 '20 at 04:04
1

The short answer is if you're using moment.js, then use it for the whole calculation (see below).

Your algorithm for subtracting 3 days doesn't work because the algorithm is wrong. A "working" version of the OP code is at the bottom. Given:

var timestampMinus3Days = timestampNow - (timestampNow % (interval1H * 24 * 3)); 

where timestampNow is an ECMAScript time value and interval1H is 3.6e6 ms.

The time value is milliseconds since 1970-01-01 UTC (the ECMAScript epoch) and % is a remainder operator, which is like modulo but not quite.

The expression timestampNow % (interval1H*24*3) divides the time since the epoch by 3 days and gets the remainder, so you're setting the new date to an integer multiple of 3 days from 1 Jan 1970, not 3 days ago. So once every 3 days the calculation will return a date for 3 days ago, and on the other two days it will return a date for 1 or 2 days ago.

The remainder also includes the time in the current day UTC, so if you're getting 00:00:00 your timezone must be +0 (GMT or UTC). Others will get a time equivalent to their timezone offset and a date for the previous day if their offset from UTC is negative.

Here's how to do it with moment.js and avoid messing with time values:

// 3 days ago from now
console.log(moment().subtract(3, 'days').format('DD.MM.YYYY HH.mm.ss'));

// 3 days ago at the start of the day
console.log(moment().subtract(3, 'days').startOf('day').format('DD.MM.YYYY HH.mm.ss'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Working version of OP code:

var timestampNow = moment().valueOf();
var interval1H = 60 * 60 * 1000;
var timestampMinus3Days = timestampNow - (timestampNow % (interval1H*24*3));
console.log("Calculated time: " + moment(timestampMinus3Days).format("DD.MM.YYYY HH.mm.ss"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
RobG
  • 142,382
  • 31
  • 172
  • 209
  • Many thanks for putting so much effort in the answer. I already commented on previous answers but it seems they got deleted, so here again: It was my mistake to use that algorithm - which i successfully used to solve another problem - also to solve this problem. Regarding your answer, which is perfectly fine, I wanted to add that I needed a performant solutation as I have to do this calculation several thousand times and moment is too slow for that specific use case. Furthermore, in your second snippet, it seems you just copied my code, I don't know if this was with intention. Anyway thanks! – flo Apr 23 '20 at 09:35
  • 1
    Yes, the second snippet is your code as a runnable snippet. I could have just edited the OP but chose this strategy instead. If you want a more performant method than moment.js, you should have said that in the OP. There are plenty of questions and answers already on how to add and subtract days from a date. A POJS solution is only [33% faster](https://jsbench.me/xck9cm3qyi/1) than moment.js, there are no simple, funky, superfast ways of doing what you want to do. – RobG Apr 23 '20 at 10:19