Finding Difference Between Three Values Using Moment.js - javascript

I am using a variety of moment.js methods to find the difference in milliseconds between values originally represented as dates. This is what I'm doing:
const stopTimeLong = '2021-05-19 09:54:08';
const startTimeLong = '2021-05-19 09:54:04';
const currentTimeLong = '2021-05-19 09:54:10';
// Get values in milliseconds
const stopTime = moment(stopTimeLong).valueOf();
const startTime = moment(startTimeLong).valueOf();
const currentTime = moment(currentTimeLong).valueOf();
const duration = moment.duration(stopTime - startTime).asSeconds(); // is 4
const final = moment.duration(currentTime - (stopTime - startTime)).asSeconds();
Now, the value for duration here gives me what I expect based on the initial times: 4
However the value for final is 1621432450 where I would expect 6.
What is the issue here? What do I need to change in order to get 6 as the final result based on the initial dates?

The last line should be:
const final = moment.duration(currentTime - startTime).asSeconds();
The stop time is irrelevant, based on the data you gave and the result you asked for.

Related

Time Range with an hour difference

const all = ['2021-04-26T08:00:00', '2021-04-27T10:00:00',]
const range = ["2021-04-26T00:00:00.000Z",
"2021-04-26T01:00:00.000Z",
"2021-04-26T02:00:00.000Z",
"2021-04-26T03:00:00.000Z",
"2021-04-26T04:00:00.000Z",
"2021-04-26T05:00:00.000Z",
"2021-04-26T06:00:00.000Z",
"2021-04-26T07:00:00.000Z",
"2021-04-26T08:00:00.000Z",
"2021-04-27T00:00:00.000Z",
"2021-04-27T01:00:00.000Z",
"2021-04-27T02:00:00.000Z",
"2021-04-27T03:00:00.000Z",
"2021-04-27T04:00:00.000Z",
"2021-04-27T05:00:00.000Z",
"2021-04-27T06:00:00.000Z",
"2021-04-27T07:00:00.000Z",
"2021-04-27T08:00:00.000Z",
"2021-04-27T09:00:00.000Z",
"2021-04-27T10:00:00.000Z"
]
console.log(all, range)
is it possible to loop over a list of date like (all) and get all time range from midnight with moment.js like (range)
🙏🏻 any hint
Below is an example of achieving this. It simply loops until it finds the matching end timestamp and keeps pushing the ISO strings to the ranges array.
const all = ['2021-04-26T08:00:00Z', '2021-04-27T10:00:00Z'];
const end = moment(all[1]);
let current = moment(all[0]).startOf('day');
const ranges = [];
while (!current.isSame(end)) {
ranges.push(current.toISOString());
current = current.add(1, 'hour');
}
console.log(ranges);
<script src="https://cdn.jsdelivr.net/npm/moment#2.29.1/moment.js"></script>

Leading and trailing zeros in numbers

I am working on a project where I require to format incoming numbers in the following way:
###.###
However I noticed some results I didn't expect.
The following works in the sense that I don't get an error:
console.log(07);
// or in my case:
console.log(007);
Of course, it will not retain the '00' in the value itself, since that value is effectively 7.
The same goes for the following:
console.log(7.0);
// or in my case:
console.log(7.000);
JavaScript understands what I am doing, but in the end the actual value will be 7, which can be proven with the following:
const leadingValue = 007;
const trailingValue = 7.00;
console.log(leadingValue, trailingValue); // both are exactly 7
But what I find curious is the following: the moment I combine these two I get a syntax error:
// but not this:
console.log(007.000);
1) Can someone explain why this isn't working?
I'm trying to find a solution to store numbers/floats with the exact precision without using string.
2) Is there any way in JS/NodeJS or even TypeScript to do this without using strings?
What I currently want to do is to receive the input, scan for the format and store that as a separate property and then parse the incoming value since parseInt('007.000') does work. And when the user wants to get this value return it back to the user... in a string.. unfortunately.
1) 007.000 is a syntax error because 007 is an octal integer literal, to which you're then appending a floating point part. (Try console.log(010). This prints 8.)
2) Here's how you can achieve your formatting using Intl.NumberFormat...
var myformat = new Intl.NumberFormat('en-US', {
minimumIntegerDigits: 3,
minimumFractionDigits: 3
});
console.log(myformat.format(7)); // prints 007.000
Hi
You can use an aproach that uses string funtions .split .padStart and .padEnd
Search on MDN
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
Here you have an example:
const x = 12.1;
function formatNumber( unformatedNumber) {
const desiredDecimalPad = 3;
const desiredNonDecimalPad = 3;
const unformatedNumberString = unformatedNumber.toString();
const unformatedNumberArr = unformatedNumberString.split('.');
const decimalStartPadded = unformatedNumberArr[0].padStart(desiredDecimalPad, '0');
const nonDecimalEndPadded = unformatedNumberArr[1].padEnd(desiredNonDecimalPad, '0');
const formatedNumberString = decimalStartPadded + '.' + nonDecimalEndPadded;
return formatedNumberString;
}
console.log(formatNumber(x))

Moment locale not working - getting values in English

I am trying to set the language of moment in a function, like this:
moment.locale('nb');
const fraDato = moment('2018-05-01', 'YYYY-MM-DD').format('MMMM');
const tilDato = moment('2018-07-01', 'YYYY-MM-DD').format('MMMM');
const months = moment.months();
const fromIndex = months.findIndex(month => month === fraDato);
const toIndex = months.findIndex(month => month === tilDato) + 1;
const range = months.slice(fromIndex, toIndex);
console.log(range);
I get the returned values in English.
Here is the fiddle for it.
How can I make this work with local set to different language?
You have it misspelled. It should be moment.locale('nd');.
Check it here.

Execution time with process.hrtime() return vastly different result

I'm having trouble explaining why my performance test return significantly different results on 2 different types of run.
Steps to reproduce issue:
Get the code from gist:
https://gist.github.com/AVAVT/83685bfe5280efc7278465f90657b9ea
Run node practice1.generator
Run node practice1.performance-test
practice1.generator should generate a test-data.json file, and log some searching algorithm execution time into the console.
After that, practice1.performance-test reads from test-data.json, and perform the exact same evaluation function on that same data.
The output on my machine is consistently similar to this:
> node practice1.generator
Generate time: 9,307,061,368 nanoseconds
Total time using indexOf : 7,005,750 nanoseconds
Total time using for loop : 7,463,967 nanoseconds
Total time using binary search : 1,741,822 nanoseconds
Total time using interpolation search: 915,532 nanoseconds
> node practice1.performance-test
Total time using indexOf : 11,574,993 nanoseconds
Total time using for loop : 8,765,902 nanoseconds
Total time using binary search : 2,365,598 nanoseconds
Total time using interpolation search: 771,005 nanoseconds
Note the difference in execution time in the case of indexOf and binary search comparing to the other algorithms.
If I repeatedly run node practice1.generator or node practice1.performance-test, the result is quite consistent though.
Now this is so troubling, I can't find a way to figure out which result is credible, and why such differences occur. Is it caused by a difference between the generated test array vs JSON.parse-d test array; or is it caused by process.hrtime(); or is it some unknown reason I couldn't even fathom?
Update: I have traced the cause of the indexOf case to be because of JSON.parse. Inside practice1.generator, the tests array is the original generated array; while in practice1.performance-test the array is read from the json file and is probably different from the original array somehow.
If within practice1.generator I instead JSON.parse() a new array from the string:
var tests2 = JSON.parse(JSON.stringify(tests));
performanceUtil.performanceTest(tests2);
The execution time of indexOf is now consistent on both files.
> node practice1.generator
Generate time: 9,026,080,466 nanoseconds
Total time using indexOf : 11,016,420 nanoseconds
Total time using for loop : 8,534,540 nanoseconds
Total time using binary search : 1,586,780 nanoseconds
Total time using interpolation search: 742,460 nanoseconds
> node practice1.performance-test
Total time using indexOf : 11,423,556 nanoseconds
Total time using for loop : 8,509,602 nanoseconds
Total time using binary search : 2,303,099 nanoseconds
Total time using interpolation search: 718,723 nanoseconds
So at least I know indexOf run better on the original array and worse on a JSON.parse-d array. Still I only know the reason, no clue why.
The Binary search execution time remain different on 2 files, consistently taking ~1.7ms in practice1.generator (even when using a JSON.parse-d object) and ~2.3ms in practice1.performance-test.
Below is the same code as in the gist, provided for future reference purpose.
performance-utils.js:
'use strict';
const performanceTest = function(tests){
var tindexOf = process.hrtime();
tests.forEach(testcase => {
var result = testcase.input.indexOf(testcase.target);
if(result !== testcase.output) console.log("Errr", result, testcase.output);
});
tindexOf = process.hrtime(tindexOf);
var tmanual = process.hrtime();
tests.forEach(testcase => {
const arrLen = testcase.input.length;
var result = -1;
for(var i=0;i<arrLen;i++){
if(testcase.input[i] === testcase.target){
result = i;
break;
}
}
if(result !== testcase.output) console.log("Errr", result, testcase.output);
});
tmanual = process.hrtime(tmanual);
var tbinary = process.hrtime();
tests.forEach(testcase => {
var max = testcase.input.length-1;
var min = 0;
var check, num;
var result = -1;
while(max => min){
check = Math.floor((max+min)/2);
num = testcase.input[check];
if(num === testcase.target){
result = check;
break;
}
else if(num > testcase.target) max = check-1;
else min = check+1;
}
if(result !== testcase.output) console.log("Errr", result, testcase.output);
});
tbinary = process.hrtime(tbinary);
var tinterpolation = process.hrtime();
tests.forEach(testcase => {
var max = testcase.input.length-1;
var min = 0;
var result = -1;
var check, num;
while(max > min && testcase.target >= testcase.input[min] && testcase.target <= testcase.input[max]){
check = min + Math.round((max-min) * (testcase.target - testcase.input[min]) / (testcase.input[max]-testcase.input[min]));
num = testcase.input[check];
if(num === testcase.target){
result = check;
break;
}
else if(testcase.target > num) min = check + 1;
else max = check - 1;
}
if(result === -1 && testcase.input[max] == testcase.target) result = max;
if(result !== testcase.output) console.log("Errr", result, testcase.output);
});
tinterpolation = process.hrtime(tinterpolation);
console.log(`Total time using indexOf : ${(tindexOf[0] * 1e9 + tindexOf[1]).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")} nanoseconds`);
console.log(`Total time using for loop : ${(tmanual[0] * 1e9 + tmanual[1]).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")} nanoseconds`);
console.log(`Total time using binary search : ${(tbinary[0] * 1e9 + tbinary[1]).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")} nanoseconds`);
console.log(`Total time using interpolation search: ${(tinterpolation[0] * 1e9 + tinterpolation[1]).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")} nanoseconds`);
}
module.exports = { performanceTest }
practice1.generator.js:
'use strict';
require('util');
const performanceUtil = require('./performance-utils');
const fs = require('fs');
const path = require('path');
const outputFilePath = path.join(__dirname, process.argv[3] || 'test-data.json');
const AMOUNT_TO_GENERATE = parseInt(process.argv[2] || 1000);
// Make sure ARRAY_LENGTH_MAX < (MAX_NUMBER - MIN_NUMBER)
const ARRAY_LENGTH_MIN = 10000;
const ARRAY_LENGTH_MAX = 18000;
const MIN_NUMBER = -10000;
const MAX_NUMBER = 10000;
const candidates = Array.from(Array(MAX_NUMBER - MIN_NUMBER + 1), (item, index) => MIN_NUMBER + index);
function createNewTestcase(){
var input = candidates.slice();
const lengthToGenerate = Math.floor(Math.random()*(ARRAY_LENGTH_MAX - ARRAY_LENGTH_MIN + 1)) + ARRAY_LENGTH_MIN;
while(input.length > lengthToGenerate){
input.splice(Math.floor(Math.random()*input.length), 1);
}
const notfound = input.length === lengthToGenerate ?
input.splice(Math.floor(Math.random()*input.length), 1)[0] : MIN_NUMBER-1;
const output = Math.floor(Math.random()*(input.length+1)) - 1;
const target = output === -1 ? notfound : input[output];
return {
input,
target,
output
};
}
var tgen = process.hrtime();
var tests = [];
while(tests.length < AMOUNT_TO_GENERATE){
tests.push(createNewTestcase());
}
fs.writeFileSync(outputFilePath, JSON.stringify(tests));
var tgen = process.hrtime(tgen);
console.log(`Generate time: ${(tgen[0] * 1e9 + tgen[1]).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")} nanoseconds`);
performanceUtil.performanceTest(tests);
practice1.performance-test.js:
'use strict';
require('util');
const performanceUtil = require('./performance-utils');
const fs = require('fs');
const path = require('path');
const outputFilePath = path.join(__dirname, process.argv[2] || 'test-data.json');
var tests = JSON.parse(fs.readFileSync(outputFilePath));
performanceUtil.performanceTest(tests);
As you have already noticed, the performance difference leads to the comparison: generated array vs JSON.parsed. What we have in both cases: same arrays with same numbers? So the look up performance must be the same? No.
Every Javascript engine has various data type structures for representing same values(numbers, objects, arrays, etc). In most cases optimizer tries to find out the best data type to use. And also often generates some additional meta information, like hidden clases or tags for arrays.
There are several very nice articles about the data types:
v8-perf/data-types
v8 performance tips
So why arrays created by JSON.parse are slow? The parser, when creating values, doesn't properly optimize the data structures, and as the result we get untagged arrays with boxed doubles. But we can optimize the arrays afterwards with Array.from and in your case, same as the generated arrays, you get smi arrays with smi numbers. Here is an example based on your sample.
const fs = require('fs');
const path = require('path');
const outputFilePath = path.join(__dirname, process.argv[2] || 'test-data.json');
let tests = JSON.parse(fs.readFileSync(outputFilePath));
// for this demo we take only the first items array
var arrSlow = tests[0].input;
// `slice` copies array as-is
var arrSlow2 = tests[0].input.slice();
// array is copied and optimized
var arrFast = Array.from(tests[0].input);
console.log(%HasFastSmiElements(arrFast), %HasFastSmiElements(arrSlow), %HasFastSmiElements(arrSlow2));
//> true, false, false
console.log(%HasFastObjectElements(arrFast), %HasFastObjectElements(arrSlow), %HasFastObjectElements(arrSlow2));
//> false, true, true
console.log(%HasFastDoubleElements(arrFast), %HasFastDoubleElements(arrSlow), %HasFastDoubleElements(arrSlow2));
//> false, false, false
// small numbers and unboxed doubles in action
console.log(%HasFastDoubleElements([Math.pow(2, 31)]));
console.log(%HasFastSmiElements([Math.pow(2, 30)]));
Run it with node --allow-natives-syntax test.js
OK...first of all lets talk about testing strategy...
Running this tests several times gives incredible different results fluctuating a lot for each point... see results here
https://docs.google.com/spreadsheets/d/1Z95GtT85BljpNda4l-usPjNTA5lJtUmmcY7BVB8fFGQ/edit?usp=sharing
After test update (running 100 tests in a row and calculating average) I score that the main difference in execution times are:
the indexOf and for loops are working better in GENERATOR scenario
the binary search and interpolation search are working better in JSON-parse scenario
Please look at the google doc before...
OK.. Great... This thing is much more easier to explain... basicly we trapped into situation when RANDOM memory access(binary, interpolation search) and CONSECUTIVE memory access(indexOf, for) give different results
Hmmm. Lets go deeper inside the memory management model of NodeJS
First of all NodeJS has several array representations, I actually know only two - numberArray, objectArray(means array that can include value of any type)
Lets look at GENERATOR scenario:
During initial array creation NodeJS is ABLE to detect that your array contains only numbers, as array starting from only numbers, and nothing of other type is added to it. This results in using simple memory allocation strategy, just raw row of integers going one by one in memory...
Array is represented as array of raw numbers in memory, most likely only memory paging table has an effect here
This fact clearly explains why CONSECUTIVE memory access works better in this case.
Lets look at JSON-parse scenario:
During the JSON parsing structure of JSON is unpredictable(NodeJS uses a stream JSON parser(99.99% confidence)), every value is tracted as most cozy for JSON parsing, so...
Array is represented as array of references to the numbers in memory, just because while parsing JSON this solution is more productive in most cases (and nobody cares (devil) )
As far as we allocating memory in heap by small chunks memory gets filled in more fluid way
Also in this model RANDOM memory access gives better results, because NodeJS engine has no options - to optimize access time it creates good either prefix tree either hash map which gives constant access time in RANDOM memory access scenarios
And this is quite good explanation why JSON-parse scenario wins during binary, interpolation search

How to ask an API for many values (of the past 14 days) via iterative timestamp manipulation?

I want to calculate the RSI - (Relative Strength Index)(Last 14 Days) for the Bitcoin-Price. The necessary data for the past 14 days comes from an API. The result should be stored in a variable for further processing. I tried different methods, but the result wasn´t working. I think i don´t found the right way to solve this. I was not able to create a complete and working result, so I am here to ask my first question on Stack Overflow.
How can I ask the API for the course of the past 14 days via
iterative timestamp manipulation?
Timestamp now -1day/-2days.... (&ts=xxxxxxxxxxxx) - example: (ts=1452680400)
https://min-api.cryptocompare.com/data/pricehistorical?fsym=BTC&tsyms=USD&ts=1452680400
How can i put the values from the API in an array?:
var closePrices= {
var : 'text',
array: [BTCDay1, BTCDay2, BTCDay3, BTCDay4, BTCDay5, BTCDay6, BTCDay7, BTCDay8, BTCDay9, BTCDay10, BTCDay11, BTCDay12, BTCDay13, BTCDay14]
};
Then I want to put the array in this calculation formular:
public static double CalculateRsi(IEnumerable<double> closePrices)
{
var prices = closePrices as double[] ?? closePrices.ToArray();
double sumGain = 0;
double sumLoss = 0;
for (int i = 1; i < prices.Length; i++)
{
var difference = prices[i] - prices[i - 1];
if (difference >= 0)
{
sumGain += difference;
}
else
{
sumLoss -= difference;
}
}
if (sumGain == 0) return 0;
if (Math.Abs(sumLoss) < Tolerance) return 100;
var relativeStrength = sumGain / sumLoss;
return 100.0 - (100.0 / (1 + relativeStrength));
}
Several quite broad questions (it usually works better if you post some of the code you already tried to write yourself)... But fun ones to solve.
Assuming we can use es6 syntax, Promises and fetch (if you can't, look up how to polyfill & transpile).
Creating an array of timestamps
To get a timestamp for the current date, you write Date.now(). To change this time stamp to a day n days ago, we decrease it by the number of milliseconds in a day:
const timeStampForDaysAgo =
nrOfDays => Date.now() - 1000 * 60 * 60 * 24 * nrOfDays;
// e.g.: yesterday
const yesterday = timeStampForDaysAgo(1);
Now, if we fill an array of the integers 0...14, we can use map to create an array of timestamps!
const lastTwoWeeks = Array.from(Array(14), (_, i) => timeStampForDaysAgo(i))
Doing the requests
In modern browsers, you can use fetch to do requests. We'll need a list of URLs though, not just timestamps. To make the URLs, we again use map:
const urls = lastTwoWeeks.map(ts => `https://your-url.com?ts=${ts}`);
Now that we have URLs, we can create our requests (again, using map):
const btcRequests = urls.map(url => fetch(url).then(r => r.json()));
Calculating the result
We can't start calculating the result until all requests have finished. That's where Promise.all comes in:
Promise.all(btcRequests).then(calcRSI);
This makes sure we only call calcRSI until all requests have finished.
Because the API returns objects of { BTC: { USD: Number } }, we'll have to extract the numbers before we can do our math.
Promise
.all(btcRequests)
.then(responses => responses.map(obj => obj.BTC.USD))
Now that we have an array of numbers, we can finally call the calculate function you gave in C# code. Of course, you'll have to translate it to javascript first.
const calcRSI = (arrayOfValues) => /* do math, return value */
Promise
.all(btcRequests)
.then(responses => responses.map(obj => obj.BTC.USD))
.then(calcRSI)
.then(rsi => console.log("The RSI for the last 14 days, is:", rsi);
See the code in action in this fiddle (make sure to open the console)

Categories