{"id":28264441,"url":"https://github.com/noahwillcrow/roblox-ts_timespan","last_synced_at":"2026-02-27T10:45:11.796Z","repository":{"id":290280821,"uuid":"973910651","full_name":"noahwillcrow/roblox-ts_timespan","owner":"noahwillcrow","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-24T02:29:23.000Z","size":72,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-24T06:44:12.395Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/noahwillcrow.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,"zenodo":null}},"created_at":"2025-04-28T01:14:08.000Z","updated_at":"2026-01-24T02:29:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"ea0a5a0a-3b4e-49fb-919f-ba256e8f6324","html_url":"https://github.com/noahwillcrow/roblox-ts_timespan","commit_stats":null,"previous_names":["noahwillcrow/roblox-ts_timespan"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/noahwillcrow/roblox-ts_timespan","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noahwillcrow%2Froblox-ts_timespan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noahwillcrow%2Froblox-ts_timespan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noahwillcrow%2Froblox-ts_timespan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noahwillcrow%2Froblox-ts_timespan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/noahwillcrow","download_url":"https://codeload.github.com/noahwillcrow/roblox-ts_timespan/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noahwillcrow%2Froblox-ts_timespan/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29892055,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T09:48:51.284Z","status":"ssl_error","status_checked_at":"2026-02-27T09:48:43.992Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2025-05-20T09:10:39.904Z","updated_at":"2026-02-27T10:45:11.784Z","avatar_url":"https://github.com/noahwillcrow.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @rbxts/timespan\n\nA simple `TimeSpan` implementation for **roblox-ts** that stores time units down to millisecond precision. This utility facilitates time arithmetic, comparisons, and custom string formatting.\n\nIt also automatically registers **Luau metamethods**, making it seamless to use in mixed TypeScript/Luau environments.\n\n## Installation\n\n```bash\nnpm i @rbxts/timespan\n```\n\n## Basic Usage\n\n### Creating TimeSpans\n\nYou can create a `TimeSpan` from specific units or by calculating the difference between two `DateTime` objects.\n\n```typescript\nimport { TimeSpan } from \"@rbxts/timespan\";\n\n// From specific units\nconst fiveSeconds = TimeSpan.fromSeconds(5);\nconst oneHour = TimeSpan.fromHours(1);\n\n// From component parts (Days, Hours, Minutes, Seconds, Milliseconds)\nconst specific = TimeSpan.create(1, 4, 30, 0, 0); // 1 day, 4 hours, 30 mins\n\n// Zero TimeSpan\nconst zero = TimeSpan.zero; // 0 milliseconds\n\n// From DateTime delta (b - a)\nconst now = DateTime.now();\nconst later = DateTime.fromUnixTimestamp(now.UnixTimestamp + 60);\nconst diff = TimeSpan.fromBetweenDateTimes(now, later); // 60 seconds\n```\n\n### Arithmetic\n\nTimeSpans are immutable; operations return a new `TimeSpan` instance.\n\n```typescript\nconst t1 = TimeSpan.fromMinutes(5);\nconst t2 = TimeSpan.fromSeconds(30);\n\nconst total = t1.add(t2);       // 5m 30s\nconst doubled = total.mul(2);   // 11m 0s\n\n// Division (Scaling)\nconst half = total.div(2);      // 2m 45s\n\n// Ratio (TimeSpan / TimeSpan)\nconst ratio = t1.ratio(t2);     // 10 (300s / 30s)\n\n// DateTime integration\nconst futureDate = total.addTo(DateTime.now());\n```\n\n### Reading Values\n\nThere is a distinction between **Total** values (the whole span converted to a unit) and **Component** values (the partial unit, like the \"30\" in \"1 hour 30 minutes\").\n\n```typescript\nconst span = TimeSpan.fromMinutes(90); // 1 hour, 30 minutes\n\n// Total values\nprint(span.totalMinutes()); // 90\nprint(span.totalHours());   // 1.5\n\n// Component values\nprint(span.hours());        // 1\nprint(span.minutes());      // 30\n```\n\n### Comparison\n\nIncludes standard comparisons and short-hand aliases (`eq`, `gt`, `lte`).\n\n```typescript\nconst t1 = TimeSpan.fromSeconds(10);\nconst t2 = TimeSpan.fromSeconds(20);\n\nif (t2.gt(t1)) {\n    print(\"t2 is greater than t1\");\n}\n\n// Check with epsilon tolerance (defaults to 2^-10 ms)\nif (t1.isCloseTo(t2)) { ... }\n```\n\n## Luau Support (Metatables)\n\nThis package automatically sets up metatables for the `TimeSpan` object. This allows you (or other scripts in your game) to use standard Lua operators.\n\n| Operator | Action | Logic |\n| --- | --- | --- |\n| `+` | Add | `TimeSpan + TimeSpan` |\n| `-` | Subtract | `TimeSpan - TimeSpan` |\n| `*` | Multiply | `TimeSpan * number` (Commutative) |\n| `/` | Scale | `TimeSpan / number` (Returns **TimeSpan**) |\n| `/` | Ratio | `TimeSpan / TimeSpan` (Returns **number**) |\n| `tostring` | Format | Calls `.toString()` default |\n| `==`, `\u003c`, `\u003c=` | Compare | Equality and Order checks |\n\n**Luau Example:**\n\n```lua\nlocal t1 = TimeSpan.fromSeconds(10)\nlocal t2 = TimeSpan.fromSeconds(5)\n\nprint(t1 + t2) -- 15s (TimeSpan)\nprint(t1 * 2)  -- 20s (TimeSpan)\nprint(2 * t1)  -- 20s (TimeSpan)\n\n-- Division behavior depends on the operand\nprint(t1 / 2)  -- 5s (TimeSpan)\nprint(t1 / t2) -- 2  (number: how many times t2 fits in t1)\n\n-- String conversion\nprint(t1)      -- \"00.00:00:10.000\" (default format)\n```\n\n## String Formatting\n\nThe `toString(format?)` method accepts a custom format string. If no format is provided, it defaults to `%{S}%{DD}.%{HH}:%{MM}:%{ss}.%{mmm}`.\n\n| Token | Description | Example |\n| --- | --- | --- |\n| `%{S}` | Sign (`-` or empty) | `-` |\n| `%{D}` | Days | `1` |\n| `%{DD}` | Days (min 2 digits) | `01` |\n| `%{H}` | Hours | `5` |\n| `%{HH}` | Hours (min 2 digits) | `05` |\n| `%{M}` | Minutes | `9` |\n| `%{MM}` | Minutes (min 2 digits) | `09` |\n| `%{s}` | Seconds | `4` |\n| `%{ss}` | Seconds (min 2 digits) | `04` |\n| `%{m}` | Milliseconds | `50` |\n| `%{mmm}` | Milliseconds (min 3 digits) | `050` |\n\n**Example:**\n\n```typescript\nconst t = TimeSpan.fromSeconds(65.5);\nprint(t.toString(\"%{m}m %{s}s\")); // \"1m 5s\"\n```\n\n---\n\n### List of API Methods\n\n| Category | Methods |\n| --- | --- |\n| **Constructors** | `fromMilliseconds`, `fromSeconds`, `fromMinutes`, `fromHours`, `fromDays`, `fromBetweenDateTimes`, `create`, `zero` |\n| **Accessors** | `totalMilliseconds`, `totalSeconds`, `totalMinutes`, `totalHours`, `totalDays` |\n| **Components** | `milliseconds`, `seconds`, `minutes`, `hours`, `days` |\n| **Absolute Components** | `absMilliseconds`, `absSeconds`, `absMinutes`, `absHours`, `absDays` |\n| **Arithmetic** | `add`, `sub`, `mul`, `div`, `ratio`, `addTo`, `subtractFrom` |\n| **Logic** | `isEqualTo` (`eq`), `isGreaterThan` (`gt`), `isLessThan` (`lt`), `isGreaterThanOrEqualTo` (`gte`), `isLessThanOrEqualTo` (`lte`), `isCloseTo` (`close`) |","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoahwillcrow%2Froblox-ts_timespan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoahwillcrow%2Froblox-ts_timespan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoahwillcrow%2Froblox-ts_timespan/lists"}