nushell: `month`, `yr` and `dec` durations are broken

hellord 👋 😋

Describe the bug

given what into duration does, i think yr, month and dec should be part of the “duration set”, but it looks like nushell does not recognize them 🤔

✔️ the following work fine

> [1ns 1us 1ms 1sec 1min 1hr 1day 1wk]
╭───┬──────╮
│ 0 │  1ns │
│ 1 │  1µs │
│ 2 │  1ms │
│ 3 │ 1sec │
│ 4 │ 1min │
│ 5 │  1hr │
│ 6 │ 1day │
│ 7 │  1wk │
╰───┴──────╯

❌ but these do not work…

> "1month" | into duration
Error: nu::shell::cant_convert_with_value (link)

  × Can't convert string `1month` to duration.
   ╭─[entry #53:1:1]
 1 │ "1month" | into duration
   · ────┬───   ──────┬──────
   ·     │            ╰── can't be converted to duration
   ·     ╰── this string value...
   ╰────
  help: supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec
> "1yr" | into duration
Error: nu::shell::cant_convert_with_value (link)

  × Can't convert string `1yr` to duration.
   ╭─[entry #54:1:1]
 1 │ "1yr" | into duration
   · ──┬──   ──────┬──────
   ·   │           ╰── can't be converted to duration
   ·   ╰── this string value...
   ╰────
  help: supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec
> "1dec" | into duration
Error: nu::shell::cant_convert_with_value (link)

  × Can't convert string `1dec` to duration.
   ╭─[entry #55:1:1]
 1 │ "1dec" | into duration
   · ───┬──   ──────┬──────
   ·    │           ╰── can't be converted to duration
   ·    ╰── this string value...
   ╰────
  help: supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec

Note what’s really strange and looks like a bug, either in the doc or in the code, is that nushell says

help: supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec

How to reproduce

  1. [1ns 1us 1ms 1sec 1min 1hr 1day 1wk] works
  2. [1ns 1us 1ms 1sec 1min 1hr 1day 1wk] | into duration works
  3. "1month" | into duration gives a nu::shell::cant_convert_with_value error
  4. "1yr" | into duration gives a nu::shell::cant_convert_with_value error
  5. "1dec" | into duration gives a nu::shell::cant_convert_with_value error

Expected behavior

depending on where the bug really comes from

  • remove “month”, “yr” and “dec” from the help message in the nu::shell::cant_convert_with_value error
  • add support for month, yr and dec back into into duration

Screenshots

No response

Configuration

key value
version 0.75.1
branch main
commit_hash f4bd78b86d441cd53fb6ff30d3a6423735a423cc
build_os linux-x86_64
build_target x86_64-unknown-linux-gnu
rust_version rustc 1.66.1 (90743e729 2023-01-10)
rust_channel 1.66.1-x86_64-unknown-linux-gnu
cargo_version cargo 1.66.1 (ad779e08b 2023-01-10)
pkg_version 0.75.1
build_time 2023-02-11 11:32:11 +01:00
build_rust_channel release
features database, default, trash, which, zip
installed_plugins

Additional context

No response

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 1
  • Comments: 17 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Checking in from the island of Bali… Not me, not for the next 2 weeks.

Regards, Bob

On Wed, Mar 15, 2023 at 12:42 AM Darren Schroeder @.***> wrote:

To quote Michael Jackson, who wants to “make that change”? 😆

— Reply to this email directly, view it on GitHub https://github.com/nushell/nushell/issues/8036#issuecomment-1469011156, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAPBIZEBWMSNYNLSA26A2KLW4D66NANCNFSM6AAAAAAUYUNQD4 . You are receiving this because you commented.Message ID: @.***>

Let me join the discussion as a complete newbie with nushell. I recently read about nushell and wanted to try it out.

So to get myself familiar with the way “piping” works in nushell I played around with the examples from the book in particular

ls | where modified >  (date now) - 2wk

If I do ls in the same directory it also shows me lots of files as “2 months ago” … so naturally I tried lots of ways of trying writing year or months , but always get type mismatch operators.

In light of the previous discussion here are 2 cents.

I realise that correct date math is hard (I guess that’s what you get from a system build on centuries of arbitrary decisions and adjustments). However, ls already does date maths. Now I know that those age indications are approximate, but as a newbie I kind of expected that I would be able somehow replicate that behaviour (even if only approximate), i.e. select files older than 2 month. Not being able to do that was certainly confusing and let me to believe I’m doing something wrong (in particular I did not find any answer in the manual why this was not working).

As I said, I understand solving this properly might not be easy, however in the interim I would suggest that ls should shows dates as absolute dates (which would also exact date calculations when comparing to the output of ls). At least there should be a note in the documentation (at the point of the example) about what durations can be specified (or a pointer to the durations docs).

Final note, I enjoy playing around with nushell, I think there’s some really great new concepts here, which make shells much more fun to work with.

This bit me again today.

Agreed. It happens to me on occasion too. I’ve changed this so many times, researched it so much that I’m kind of burnt out on it not working the way I want it to. I think the easiest fix would be to allow yr and month as f64s like.

const DAYS_PER_YEAR: f64 = 365.2422; // so many opinions https://www.universityherald.com/articles/67348/20170301/the-most-precise-number-of-days-in-a-year-according-to-scientists.htm
const DAYS_PER_MONTH: f64 = DAYS_PER_YEAR / 12; // 30.43685
const DAYS_PER_DECADE: f64 = DAYS_PER_YEAR * 10; // 3652.422

Depending on how you want to calculate what “right” means, you’ll get different answers, but if we were just to use something like this above, and document how we’re getting to those numbers, at least we’d have something more helpful.

So much stuff about what “right” means on the web that it can get quite overwhelming at times. Here’s another way to calculate days per month, which is close to what i have above. The Gregorian calendar system we use cycles every 400 years, which is 4800 months. In a cycle, there are 7 x 400 = 2800 months of 31 days, there are 4 x 400 = 1600 months of 30 days, there are 300 +3 = 303 months of 28 days, and there are 100 - 3 = 97 months of 29 days. Taking the weighted mean, the average number of days in a month is (2800 x 31 + 1600 x 30 + 303 x 28 + 97 x 29) / 4800 = 30.436875 days exactly.

There are a couple points to consider.

  1. durations are stored as nanoseconds
  2. date math is a different thing

Here’s really what those mean. Any nanosecond can be broken down into a nushell duration that pretty printed. Currently date math will return a duration, which converted into a pretty print can be wrong.

Durations no nothing about leap years and that’s the problem. In order to do date math, you really need to know the start date and the end date and not only a bunch of nanoseconds.

In bob’s example, rewritten more simply, you can do this in nushell

2022-02-28 - 2000-02-28

and it gives the same answer 22yr 6day but that answer is actually wrong. We know that answer to be 22yr or 8036 days. You can see that answer here too https://www.timeanddate.com/date/durationresult.html?m1=2&d1=28&y1=2000&m2=2&d2=28&y2=2022

Interestingly enough, our chrono crate understand all the leap year stuff. You can do this and get the right answer in days.

> 2022-02-28 - 2000-02-28 | into duration --convert day
8036

You can also see here, that the math, to the nanosecond, is correct here.

> 2022-02-28 - 2000-02-28 | debug -r
Duration {
    val: 694310400000000000,
    span: Span {
        start: 110906,
        end: 110929,
    },
}

because that website above says the number of seconds is 694,310,400 seconds which is correct because we can do

> 694_310_400 * 1_000_000_000
694310400000000000

So, what went wrong? The problem is what I said earlier, with date math, you can’t just convert nanoseconds to a pretty-print date without knowing the start date and end date and correctly calculating the days. That amount of nanoseconds could be a sliding scale and doesn’t necessarily amount to a 22 year gap. For example, another 22 year gap is 2044-02-28 - 2022-02-28 | into duration --convert day which is 8035 days, as is 1922-02-28 - 1900-02-28 | into duration --convert day.

So, in order for date math to work in nushell, I think we’d need more than nanoseconds. We’d probably need the start date and end date to properly do date math. We could make that a new Value::DateMath or Value::DateDuration or some such value.

I’d love for this thesis to be proven wrong, so feel free to challenge my position.