{"id":20510315,"url":"https://github.com/frobware/ts","last_synced_at":"2025-10-24T12:13:09.721Z","repository":{"id":220879759,"uuid":"752469382","full_name":"frobware/ts","owner":"frobware","description":"Timestamp standard input","archived":false,"fork":false,"pushed_at":"2024-06-14T19:02:56.000Z","size":95,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-24T07:38:26.492Z","etag":null,"topics":["c","moreutils","timestamp","ts"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/frobware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-03T23:36:14.000Z","updated_at":"2024-06-14T19:03:00.000Z","dependencies_parsed_at":"2024-03-15T20:49:51.700Z","dependency_job_id":"b7a7887c-0521-4bf8-bce4-c1c098843ed1","html_url":"https://github.com/frobware/ts","commit_stats":null,"previous_names":["frobware/ts"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frobware%2Fts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frobware%2Fts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frobware%2Fts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frobware%2Fts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/frobware","download_url":"https://codeload.github.com/frobware/ts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242112691,"owners_count":20073651,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","moreutils","timestamp","ts"],"created_at":"2024-11-15T20:28:59.252Z","updated_at":"2025-10-24T12:13:04.660Z","avatar_url":"https://github.com/frobware.png","language":"C","readme":"# TS (timestamp standard input)\n\n## Overview\n\nThis utility, a C reimplementation of the `ts` command from the\n[`moreutils`](https://joeyh.name/code/moreutils/) package, is designed\nto add a timestamp to the beginning of each line of input, enhancing\nthe readability and utility of log files or any streamed output. It\ncan also convert existing timestamps in the input to either absolute\nor relative times, supporting a variety of common timestamp formats.\n\nPlease note that this repository does not offer pre-built binaries,\nrequiring users to build from source.\n\n### Motivation\n\nThe primary motivation behind reimplementing the `ts` utility was to\neliminate the dependency on Perl and its associated packages. This\ndecision was driven by the goal of simplifying deployment, especially\nin containerised or constrained environments where minimising the\nfootprint is essential.\n\nWhile this version eliminates the dependency on Perl and its\nassociated packages, it requires the [PCRE](https://www.pcre.org/)\nlibrary for regular expression support, both at build and runtime.\n\n## Synopsis\n\n```plaintext\nts [-r] [-i | -s] [-m] [-p \u003cprecision\u003e] [format]\n```\n\nBy default, `ts` adds a timestamp to each line using the format `%b %d\n%H:%M:%S`. Users can specify a custom format, which adheres to the\nconventions used by `strftime(3)`, with extensions for microsecond\nresolution using the specifiers `%.S`, `%.s`, or `%.T`.\n\n- **Relative Time Conversion (`-r`)**: When used, `ts` converts\n  existing timestamps within the input into relative times (e.g.,\n  \"15m5s ago\"), automatically detecting and supporting many common\n  timestamp formats. If a custom output format is also specified with\n  `-r`, `ts` will use it for the time conversion.\n\n- **Incremental Timestamps**: The `-i` and `-s` flags alter the\n  utility's behaviour to report timestamps incrementally:\n    - **`-i`**: Each timestamp represents the time elapsed since the last timestamp.\n    - **`-s`**: Timestamps represent the time elapsed since the start of the `ts` command execution.\n\n    The default format for incremental timestamps is `%H:%M:%S`.\n\n- **Monotonic Clock (`-m`)**: Opting for this flag makes `ts` use the\n  system's monotonic clock, ensuring that the timestamps are not\n  affected by changes in the system clock.\n\n- **Precision (`-p`)**: This version of `ts` introduces the `-p`\n  option as an extension to the\n  [`moreutils`](https://joeyh.name/code/moreutils/) version of `ts`,\n  providing users with the ability to specify the precision of time\n  units in the output when using the `-r` flag for relative time\n  differences. Valid precision levels are 1 to 4 inclusive.\n\n  The default precision level is 2.\n\nThe `TZ` environment variable is respected, influencing the timezone\nused for timestamps when not explicitly included in the timestamp's\nformat.\n\n### Examples\n\n```bash\n# Basic timestamping.\n$ echo \"Log entry\" | ts\nFeb 05 21:00:42 Log entry\n\n# Custom format.\n$ echo \"Another log entry\" | ts \"%Y-%m-%d %H:%M:%S\"\n2024-02-05 21:00:52 Another log entry\n\n# Relative times.\n$ cat log.txt | ts -r\n27d4h ago host syslogd[441]: Statistics\n\n# Incremental timestamps since last event.\n$ echo -e \"foo\\nbar\\nbaz\" | while IFS= read -r line; do echo \"$line\"; sleep 2; done | ts -i\n00:00:00 foo\n00:00:02 bar\n00:00:02 baz\n\n# Incremental timestamps since start.\n$ echo -e \"foo\\nbar\\nbaz\" | while IFS= read -r line; do echo \"$line\"; sleep 2; done | ts -s\n00:00:00 foo\n00:00:02 bar\n00:00:04 baz\n\n# Custom format using the monotonic clock.\n$ echo \"Process started\" | ts -m '%FT%.T'\n2024-02-05T21:13:36.848360 Process started\n\n# High precision timestamping.\n\n$ echo \"High precision event\" | ts \"%Y-%m-%d %H:%M:%.S\"\n2024-02-05 22:50:40.383986 High precision event\n\n$ echo \"High precision event\" | ts \"%F %.T\"\n2024-02-05 22:50:54.140320 High precision event\n\n$ echo \"High precision event\" | ts -m \"%.s\"\n1707173461.672750 High precision event\n\n$ echo -e \"foo\\nbar\\nbaz\" | while IFS= read -r line; do echo \"$line\"; sleep 2; done | ts -m -s %.s\n0.130000 foo\n2.172200 bar\n4.608700 baz\n```\n\n## Understanding Relative Timestamps\n\nThe `-r` flag transforms absolute timestamps into relative terms,\nsimplifying the comprehension of when events occurred. This\ntransformation includes recognising timestamps through pattern\nmatching, parsing them into component units, and approximating the\ntime difference in a user-friendly format. The process emphasises\nfocusing on non-zero units, managing rollovers, and rounding where\napplicable, ensuring the output is precise yet easily understandable.\n\n### Pattern Matching and Parsing\n\nWhen `ts` encounters a timestamp in the input, it matches it against\npredefined patterns. A successful match leads to the decomposition of\nthe timestamp into its constituent units: years, days, hours, minutes,\nand seconds. This breakdown is crucial for calculating the relative\ntime difference. Notably absent is the month unit, omitted due to its\nvariable length complicating uniform calculations. This decision\nstreamlines approximation, focusing on fixed-length units for\nconsistency and simplicity in conveying time spans.\n\n### Approximation: Focusing on Non-Zero Units\n\nThe approximation step calculates the time difference between the\ncurrent moment and the parsed timestamp, adjusting this difference to\nhighlight the most significant, relevant units:\n\n- **Focusing on Non-Zero Units:** Initially, `ts` identifies units\n  with non-zero values, prioritising them to ensure the approximation\n  highlights actual time differences rather than zero-valued units.\n  This focus is essential for clarity.\n\n- **Rollovers:** Rollover handling adjusts time units exceeding their\n  conventional maximum (e.g., 60 minutes) to the next higher unit\n  (e.g., converting 70 minutes to 1 hour and 10 minutes), maintaining\n  consistency with standard time measurement practices.\n\n- **Rounding Up:** For time units halfway or more towards their\n  maximum, `ts` will round up to simplify the representation, such as\n  approximating 1 hour and 30 minutes to \"2 hours ago.\" This rounding\n  provides a simplified yet meaningful estimate of elapsed time,\n  particularly when minute accuracy is less important than conveying a\n  general sense of duration.\n\n### Approximation: User Defined Precision\n\nPrecision ranges from 1 to 4, and determines the detail level in the\ntimestamp approximation, affecting the output's granularity and\nspecificity. The default precision level is 2.\n\nPrecision Levels Defined:\n\n- **Low Precision (1):** Best for overviews or when event occurrence\n  is more important than exact timing. This level simplifies the\n  timestamp to the single most significant non-zero unit.\n\n- **Medium Precision (2, 3)**: Balances detail and readability, suited\n  for operational logs or summarising activities. Precision 2 focuses\n  on the two most significant non-zero units, while precision 3 allows\n  for an additional layer of detail.\n\n- **High Precision (4):** Ideal for detailed logging or tracking,\n  necessary for forensic analysis or debugging. Retains all units up\n  to the four most significant non-zero units, providing a detailed\n  view without approximation.\n\n## Combining Relative timestamps with a Custom Format\n\nThe `-r` flag used with a custom format enables precise customisation\nof relative timestamp presentation according to `strftime` formatting\nrules. For example, displaying a log entry as \"Occurred on %Y-%m-%d at\n%H:%M\" instead of \"3 hours and 45 minutes ago\", applying the `-r` flag\nwith the desired custom format achieves this structured presentation\nwhile preserving the relative nature of the timing.\n\n## Monotonic clock\n\nThe [`moreutils`](https://joeyh.name/code/moreutils/) `ts`\nimplementation uses a clever approach to combine the stability of the\nmonotonic clock with the relevance of real-world timestamps. The\nmonotonic clock (CLOCK_MONOTONIC) is used for measuring time\nintervals. It is not affected by system time changes (like NTP\nadjustments or DST shifts), making it ideal for timing where\nconsistency is key. However, the monotonic clock does not represent\nreal-world time; it typically measures time since system boot.\n\nTo output meaningful timestamps while using the monotonic clock, the\nprogram calculates a 'monodelta' at startup. This is the difference\nbetween the current real-world time (CLOCK_REALTIME) and the current\nmonotonic time. By adding this delta to the monotonic timestamps, we\nadjust them to align with the real-world time. This way, the\ntimestamps output by the program represent the actual time of day,\neven though the timing is done using the monotonic clock.\n\n## Building \u0026 Installation\n\nBefore compiling the `ts` utility, you must have the\n[PCRE](https://www.pcre.org/) development library installed on your\nsystem. The development library is commonly named `pcre2-devel`,\n`libpcre2-dev`, or a similar variant, depending on your operating\nsystem and distribution.\n\n```bash\ngit clone https://github.com/frobware/ts\ncd ts\nmake INSTALL_BINDIR=$HOME/.local/bin install\n```\n\n### NixOS/Nix Support\n\nThis utility can be easily integrated into NixOS configurations or\nconsumed in Nix environments using Nix Flakes. Below is an example of\nhow to include the `ts` utility in your NixOS system or project.\n\n```nix\n{\n  description = \"Example Nix flake for integrating the `ts` utility into a NixOS configuration.\";\n\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixpkgs-unstable\";\n    ts-flake.url = \"https://github.com/frobware/ts\";\n  };\n\n  outputs = { self, nixpkgs, ts-flake, ... }@inputs:\n  let\n    pkgsWithOverlay = system: import nixpkgs {\n      inherit system;\n      overlays = [ ts-flake.overlays.default ];\n    };\n\n    buildNixOS = { system, modules }: let\n      pkgs = pkgsWithOverlay system;\n    in nixpkgs.lib.nixosSystem {\n      inherit system modules pkgs;\n    };\n  in\n  {\n    nixosConfigurations.exampleHost = buildNixOS {\n      system = \"aarch64-linux\";\n      modules = [\n        ({ pkgs, ... }: {\n          environment.systemPackages = [ pkgs.ts ];\n        })\n      ];\n    };\n  };\n}\n```\n\n## Licensing\n\nThe entire ts project, including both the source code now in C and the\nmanpage documentation, is licensed under the GNU General Public\nLicense version 2 (GPLv2). This unified licensing approach ensures\nfull compliance with the original moreutils package's licensing terms,\nfrom which the manpage documentation is verbatim copied, and aligns\nthe reimplemented `ts` utility under the same open-source license.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrobware%2Fts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrobware%2Fts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrobware%2Fts/lists"}