Page MenuHomeFreeBSD

date: Add support for nanoseconds
ClosedPublic

Authored by 0mp on Apr 22 2024, 6:41 PM.
Tags
None
Referenced Files
F101994418: D44905.id137540.diff
Wed, Nov 6, 7:53 AM
F101994240: D44905.id137539.diff
Wed, Nov 6, 7:49 AM
F101994230: D44905.id137534.diff
Wed, Nov 6, 7:49 AM
F101994227: D44905.id137538.diff
Wed, Nov 6, 7:49 AM
F101994223: D44905.id137536.diff
Wed, Nov 6, 7:49 AM
F101993946: D44905.id.diff
Wed, Nov 6, 7:43 AM
F101993858: D44905.diff
Wed, Nov 6, 7:41 AM
Unknown Object (File)
Mon, Nov 4, 10:22 AM
Subscribers

Details

Summary

This patch introduces support for a conversion specification for
nanoseconds.

The format of %N is meant to be compatible with that of GNU date.

The nanoseconds conversion specification is implemented directly in
date(1) instead of libc (around strftime(3)) to avoid introducing
non-standard functions to libc at this time.

Apart from introducing the nanoseconds conversion specification, this
patch brings the following changes:

  • The "ns" format for ISO 8061 dates is now unlocked. E.g., date -Ins prints: 2024-04-22T12:20:28,763742224+02:00
  • The -r flag when fed a file is now aware of the nanosecond part of the last modification time.
  • date(1) is now able to set the time with nanosecond precision. It is not possible as of now to do that by specifying nanoseconds directly via the command-line arguments. Instead, the -r flag can be used.
  • date(1) is now using the clock_gettime(3)-family of functions instead of ctime(3)-family of functions where possible.

Sponsored by: Klara, Inc.

Test Plan

date's tests pass.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 57292
Build 54180: arc lint + arc unit

Event Timeline

0mp requested review of this revision.Apr 22 2024, 6:41 PM
0mp added inline comments.
bin/date/date.c
356

I'm probably missing a static here.

markj added inline comments.
bin/date/date.1
591
bin/date/date.c
356

Yes.

357

I think some comment explaining what this does would be nice to have.

361

Same below. tools/build/checkstyle9.pl will catch these things.

368

size_t would be a more appropriate type for prefixlen.

375

This could be written a bit more clearly as a for loop: for (tok = newformat; *tok != '\0'; tok++) {

377

Cases should be indented by the same amount as the enclosing switch.

396

We should free() after checking rc. free() might clobber errno, which is used by err().

400

Extra newline.

bin/date/tests/format_string_test.sh
46

Can stat -f '%9Fm' testfile be used instead of this custom program?

des added inline comments.
bin/date/date.c
53–54

I find the name tspec really confusing, can you just call it ts?

59

strftimens or strftime_ns would be more descriptive. I would also just pass the nanoseconds as an additional argument instead of using a global variable.

0mp marked 8 inline comments as done.Apr 23 2024, 9:42 AM

I'll upload an updated patch shortly.

bin/date/date.c
396

I think we need to call free before err anyway to avoid a memory leak of old_format. Would it be alright if we preserved the errno value? I've included the proposed solution in the revised patch.

bin/date/tests/format_string_test.sh
46

Oh! Amazing, I could figure out from the manual page if it is possible to access the nanosecond part of the timestamp. Yes, I'll replace that custom program with stat. Thanks!

0mp marked an inline comment as done.Apr 23 2024, 9:47 AM
0mp added inline comments.
bin/date/date.c
357

I've added some comments.

368

int seems to be the required type. With size_t I get:

date.c:415:34: error: field precision should have type 'int', but argument has type 'size_t' (aka 'unsigned long') [-Werror,-Wformat]
                                rc = asprintf(&newformat, "%.*s%.9ld%s",

Update usage() and sort variable declarations in strftime_ns().

bin/date/date.c
396

The leak doesn't matter since we're terminating.

bin/date/date.c
53–54

It would be better if this wasn't a global. Just add long nsec parameters to printisodate() and setthetime().

  • Move the ts global variable to main()
    • We pass long nsec to printisodate() because printisodate() does not require the seconds part of timespec. However, setthetime does need both seconds and nanoseconds of timespec, so it makes more sense to pass the whole stuct there.
  • Simplify freeing of old_format.
0mp marked 4 inline comments as done.Apr 23 2024, 11:25 AM
0mp added inline comments.
bin/date/date.c
396

Alright, I didn't know we are allowed to take this shortcut in the src tree.

0mp marked an inline comment as done.
  • Reference clock_gettime from SEE ALSO

Looks good to me overall.

bin/date/date.c
368

I'd argue that this calls for an explicit cast to int in the asprintf() call. What you're storing here is the difference between two addresses, and size_t is the appropriate type for that.

bin/date/date.c
368

Technically the difference between two addresses is a ptrdiff_t, but you can use size_t if you are certain that it cannot be negative. And yes, you will need an explicit cast to int in the asprintf() call.

  • Remove unused variable olderrno
  • Use size_t for prefixlen
0mp marked 3 inline comments as done.Apr 25 2024, 10:38 AM
0mp added inline comments.
bin/date/date.c
368

Thank you for the feedback! I've changed the type to size_t.

markj added inline comments.
bin/date/date.c
394

Or just seen_percent = !seen_percent

This revision is now accepted and ready to land.Apr 25 2024, 1:41 PM
0mp marked 2 inline comments as done.Apr 25 2024, 2:52 PM
0mp added inline comments.
bin/date/date.c
394

I was thinking about it, but I decided to keep it simple for future readers.

0mp marked an inline comment as done.Apr 26 2024, 9:27 AM

Thank you for the review! :))

This revision was automatically updated to reflect the committed changes.