0

I want to write a function that looks like this:

function getValuesGreaterThan(num, values);

The input comes from a system call to find . -maxdepth 1 -type f -printf '%C@\n', an array of strings like [..., "1643764147.7500000000", "1643764147.7600000000", "1643764147.7700000000", ...]. The function will return an array of the values.

Although the input is an array of strings, that doesn't mean it has to stay that way: if the easiest solution to this is to convert it to a different type (e.g., a number), that's fine. The same goes for the return type--all that matters is the correct subset is returned in the same order.

But, I want to make sure the output of getValuesGreaterThan isn't affected by precision issues or coercion quirks.

I've learned that JavaScript has a BigInt type, but I can't find anything about a BigReal or a BigDecimal, etc. I'm not even sure if I need to use these; perhaps the localeCompare will work as expected on these strings?

let getValuesGreaterThan = function (num, values) {
  return values.filter((v) => v.localeCompare(num) >= 0)
}

console.log(getValuesGreaterThan("1643764147.7600000000", ["1643764147.7500000000", "1643764147.7600000000", "1643764147.7700000000"]))

It seems to work, but no matter how many experiments I think of, there could be inputs that break it.

How do I compare unix timestamps in JavaScript?

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356
  • 2
    `String#localeCompare()` compare *strings* lexicographically, so that's definitely not what you want: `'4'.localeCompare('123.456') // 1, i.e. 4 is greater` – InSync Jun 06 '23 at 00:35
  • @jabaa Whatever numeric range exists for `find . -maxdepth 1 -type f -printf '%C@\n'` – Daniel Kaplan Jun 06 '23 at 00:37
  • 2
    Is there any reason why you can't compare the integer part first, and if they're the same, then compare the decimals via localeCompare()? `const [integer, decimal] = num.split(".");` – Blair Jun 06 '23 at 00:44
  • I think you can parse the strings and mathematically compare them. The precision should be enough. These are Unix timestamps. `localeCompare` works between 2001 and 2286. – jabaa Jun 06 '23 at 00:45
  • Those are not large numbers. You have 12 significant digits. A double-precision float stores 15 or 16 digits. If you're doing arithmetic, then you worry, but if you're just comparing, there shouldn't be any problems. – Tim Roberts Jun 06 '23 at 00:46
  • @TimRoberts For the good of the community, maybe it's best to imagine they are large numbers (I can change my question)? I can't find other examples of this question being asked. – Daniel Kaplan Jun 06 '23 at 01:25
  • 1
    With a quick search I've found [decimal.js](https://github.com/MikeMcl/decimal.js), [bignumber.js](https://github.com/MikeMcl/bignumber.js/) and [math.js](https://github.com/josdejong/mathjs) which seem could do the job. – Ricky Mo Jun 06 '23 at 01:33
  • 2
    That's the danger of theoretical questions. But if your data is timestamps, then why would we need to imagine anything? We know the size and precision of Unix timestamps. There's no need for a full-precision add-on library. – Tim Roberts Jun 06 '23 at 03:40
  • @TimRoberts Good point, and if you demonstrate that in code as an answer, I'll accept it. For the community, I'll also change the title. It always bothers me when a question title is exactly what I'm looking for, but the question body asks something different; I don't want to contribute to that problem. – Daniel Kaplan Jun 06 '23 at 19:27

1 Answers1

1
  1. Create a set of shadows strings ensuring all strings have the same fractional component length (the same as longest fractional component length), by padding as required.
  2. Remove the decimal points.
  3. Convert to bigint and compare.
  4. Reflect the answers back to the original strings.
Craig Hicks
  • 2,199
  • 20
  • 35