Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support getting the current unix timestamp with status #10093

Open
orf opened this issue Nov 9, 2023 · 12 comments
Open

Support getting the current unix timestamp with status #10093

orf opened this issue Nov 9, 2023 · 12 comments

Comments

@orf
Copy link

orf commented Nov 9, 2023

Fish is a great shell with a lot of builtin utilities. I was surprised to see that there was no built-in way to get the current unix timestamp with fish. For context, I'm using a function that runs on the fish_postexec event and I'd like to record the current time of the command somewhere.

I can obviously just do date +%s, but this is surprisingly heavyweight:

❯ time date +%s
1699532413

________________________________________________________
Executed in    7.15 millis    fish           external
   usr time    1.13 millis  107.00 micros    1.02 millis
   sys time    3.11 millis  567.00 micros    2.54 millis

Compared to a built-in like status:

❯ time status --is-interactive

________________________________________________________
Executed in    5.00 micros    fish           external
   usr time    6.00 micros    6.00 micros    0.00 micros
   sys time    3.00 micros    3.00 micros    0.00 micros

5 microseconds vs 7.15 milliseconds is a big difference - that's 1430x faster!

The status command is described as a way to query fish runtime information. The current unix timestamp seems like it would fall into the category of "fish runtime information", so I'm proposing to add a status current-timestamp or status execution-timestamp command to return a simple UNIX timestamp, the same as date +%s but far faster.

There are quite a few usages of date +%s in Fish files that you can find on Github, and even more general usages of date.

We shouldn't look to emulate/replace date, but if there is a super-common use-case like grabbing the unix timestamp that currently requires using date, perhaps it's worth adding it as a builtin?

@faho
Copy link
Member

faho commented Nov 9, 2023

I have a branch lying around somewhere that adds a variable.

I think I called it $EPOCH (bash has $EPOCHSECONDS and $EPOCHREALTIME, the latter was added after someone wanted to have nanoseconds).

Looking at it again I'd probably call it $fish_time so it's less jargony and doesn't step on anyone's toes (what if someone has already made a variable called $EPOCH?).

@faho faho added this to the fish next-3.x milestone Nov 9, 2023
@Xiretza
Copy link
Contributor

Xiretza commented Nov 9, 2023

Personally I'd prefer a builtin subcommand over polluting the variable namespace even more, especially with this kind of magic variable that isn't really a variable but more of a function call.

@faho
Copy link
Member

faho commented Nov 9, 2023

There's not really a fitting builtin to add it - status is quite specifically about things inside fish - the filename, whether it's a login/interactive shell or not, which feature flags are enabled. These are all fish's own internal state.

The time is not something that happens inside of fish's own code. It is a universal thing.

Every other builtin fits even less.

Adding a variable with a fish_ prefix is not really a big deal. It's fine.

Or we refocus status somewhat and add this and possibly a uname replacement (we already call the uname() and so it seems extremely wasteful to then run the uname command whenever we do need the operating system). That has the advantage that you could do

set -l time (status current-time 2>/dev/null; or date +%s)
set -l os (status operating-system 2>/dev/null; or uname)

to have backwards-compatible code to versions before that was introduced. With variables you'd have to fiddle with set -q.

@krobelus
Copy link
Member

krobelus commented Nov 9, 2023

I wonder when date +%s is actually too slow

@orf
Copy link
Author

orf commented Nov 9, 2023

Too slow is relative: 7ms to grab the current time is definitely too slow, and grabbing the time is a pretty common thing with code related to shells and prompts.

However it's likely never a bottleneck.

The point of this suggestion is that we might not need to make our machines do all the work of spawning a process, setting up stdio/pipes, parsing the arguments and waiting for the output all to basically call clock_gettime, which is one of the fastest calls you can make.

You can make a slippery-slope argument about this, but "inlining" very common things is a good thing to do. Time functions are definitely lacking here.

IMO just including a way to grab the UNIX timestamp, and maybe the ISO 8601 timestamp, is all we should add. If you need anything more custom then use date.

@orf
Copy link
Author

orf commented Nov 9, 2023

Or we refocus status somewhat and add this and possibly a uname replacement (we already call the uname() and so it seems extremely wasteful to then run the uname command whenever we do need the operating system). That has the advantage that you could do

To me status has never really seemed to imply "only fish internal state", even if that is the intention and/or the current implementation. The name doesn't really imply it either, IMO.

Maybe we could add a machine command instead? Or platform? That being said, name clashes are obviously a problem so it might make sense to put it in status if only for that reason.

faho added a commit to faho/fish-shell that referenced this issue Nov 23, 2023
This is extremely easy to implement and can be used for all sorts of
durations.

Fixes fish-shell#10093
@Doroszewski
Copy link

I second this proposition.

Currently, the only way to have the time in one's command prompt is to have fish_prompt execute date (or one's custom executable). This requires spawning a completely new process (usually with dynamic linking) every single time the prompt appears.

Some kind of a wrapper for strftime() (e.g., string strftime) would be nice, but having the timestamp is a good starting point.

@mralusw
Copy link

mralusw commented Apr 17, 2024

EPOCHREALTIME and EPOCHSECONDS are essential for benchmarking scripts. It's impossible to measure something if the process of measurement adds an unpredictable overhead to an external command, which probably itself has layers of overhead because of history (and because it's GNU coreutils).

Depending on the various incarnations of date, gdate etc also adds a nice configuration problem for the script authors.

I wonder when date +%s is actually too slow

Isn't fish the very same shell that eschews basic subshell functionality (how's cd -l coming along BTW?) for the sake of performance?

@faho
Copy link
Member

faho commented Apr 17, 2024

EPOCHREALTIME and EPOCHSECONDS are essential for benchmarking scripts.

@mralusw If you want to profile a script, use fish --profile.

Other than that I would appreciate further comments without the digs at other issues, thank you very much.

@mralusw
Copy link

mralusw commented Apr 17, 2024

EPOCHREALTIME and EPOCHSECONDS are essential for benchmarking scripts.

@mralusw If you want to profile a script, use fish --profile.

That's very useful but it only handles profiling entire scripts. If you want to write a script to benchmark something else, or want to time a fragment of the current script, having a way to get timestamps is not easily replaceable.

Other than that I would appreciate further comments without the digs at other issues, thank you very much.

I was digging at another comment, not another issue. But the point is that if you design your shell to avoid fork(), you might as well provide ways to avoid exec()'s for some cases.

@faho
Copy link
Member

faho commented Apr 17, 2024

That's very useful but it only handles profiling entire scripts

You can profile specific code - fish --profile profile-file -c 'your commands here'.

This will also work for functions, provided they are defined in that fish (e.g. autoloaded).

And in general, a full profile is more useful for, well, profiling, than just the timestamp.

having a way to get timestamps is not easily replaceable

And that is why this issue is still open. The question is mostly where to put the functionality - $EPOCHREALTIME is a mouthful and quite jargony, a status subcommand isn't really what status is for.

I was digging at another comment, not another issue.

Regardless, I would appreciate if you could just not dig at all.

@mralusw
Copy link

mralusw commented Apr 17, 2024

And that is why this issue is still open. The question is mostly where to put the functionality - $EPOCHREALTIME is a mouthful and quite jargony, a status subcommand isn't really what status is for.

I agree, I was pointing out a separate use case.

Is there any overhead for having a builtin vs a variable? AFAICT there isn't. Other than that, at this point it seems it's (1) a string function (so it could be a string subcommand), and (2) a fish wrapper around a C library call (so it could be fish_strftime or something like that). I'd vote for providing access to full strftime format strings either way.

Regardless, I would appreciate if you could just not dig at all.

There were also digs at date, coreutils, and probably GNU, but maybe not that obvious. Anyway, sorry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants