{"id":49267706,"url":"https://github.com/bold-minds/dt","last_synced_at":"2026-04-25T11:31:07.777Z","repository":{"id":349422920,"uuid":"1202160848","full_name":"bold-minds/dt","owner":"bold-minds","description":"Datetime parsing and formatting for real-world inputs — auto-detect format, accept any, output string. Zero deps.","archived":false,"fork":false,"pushed_at":"2026-04-05T20:54:09.000Z","size":75,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-05T22:22:25.220Z","etag":null,"topics":["date-parser","datetime","datetime-parser","go","golang","time-parsing","timezone"],"latest_commit_sha":null,"homepage":null,"language":"Go","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/bold-minds.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-05T17:18:06.000Z","updated_at":"2026-04-05T22:21:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bold-minds/dt","commit_stats":null,"previous_names":["bold-minds/dt"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/bold-minds/dt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-minds%2Fdt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-minds%2Fdt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-minds%2Fdt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-minds%2Fdt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bold-minds","download_url":"https://codeload.github.com/bold-minds/dt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-minds%2Fdt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32260906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T09:15:33.318Z","status":"ssl_error","status_checked_at":"2026-04-25T09:15:31.997Z","response_time":59,"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":["date-parser","datetime","datetime-parser","go","golang","time-parsing","timezone"],"created_at":"2026-04-25T11:31:07.020Z","updated_at":"2026-04-25T11:31:07.771Z","avatar_url":"https://github.com/bold-minds.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dt\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/bold-minds/dt.svg)](https://pkg.go.dev/github.com/bold-minds/dt)\n[![Build](https://img.shields.io/github/actions/workflow/status/bold-minds/dt/test.yaml?branch=main\u0026label=tests)](https://github.com/bold-minds/dt/actions/workflows/test.yaml)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/bold-minds/dt)](go.mod)\n\n**Datetime parsing and formatting for real-world inputs — auto-detect the format, accept `any`, output a string.**\n\nGo's `time` package requires you to know the layout before parsing. That's fine for structured code, but it's friction when you're processing ingested data: user input, API payloads, log lines, config values. `dt` auto-detects the format and accepts `time.Time`, Unix timestamps, or strings interchangeably.\n\n```go\n// Parse whatever the caller passes, format as ISO 8601\ns := dt.NewDatetime(\"Jan 2, 2026\")                    // \"2026-01-02T00:00:00Z\"\ns  = dt.NewDatetime(int64(1735776000))                // \"2025-01-02T00:00:00Z\"\ns  = dt.NewDatetime(time.Now(), dt.FormatAs(dt.Unix())) // Unix millis string\n\n// Convert to time.Time when you need a real value\nt := dt.ToDatetime(\"2026-01-15T10:30:00Z\")\n```\n\n## ✨ Why dt?\n\n- 🎯 **Accepts `any`** — `time.Time`, `int64`, `int`, `float64`, or `string`. No \"first convert to...\" step.\n- 🔎 **Format auto-detection** — drop in user input, get a parsed result. Handles ISO 8601, Unix timestamps, US/European dates, natural-language month names, ordinal days.\n- 🛡️ **Never panics** — malformed input returns a zero `time.Time`, not a crash.\n- 🔒 **Parser resilience** — length-gated heuristic filter avoids quadratic behavior on non-datetime input. Unix timestamp range validation rejects implausible values.\n- 🪶 **Zero dependencies** — pure Go stdlib (`fmt`, `regexp`, `strconv`, `strings`, `time`).\n- 🌍 **Timezone and format options** — convert to a target timezone, strip date or time components, choose between ISO / Unix / custom output patterns.\n\n## 📦 Installation\n\n```bash\ngo get github.com/bold-minds/dt\n```\n\nRequires Go 1.21 or later.\n\n\u003e **Go version support.** `dt` intentionally targets Go 1.21 as its floor so\n\u003e the Goby library family maintains broad source compatibility. Go 1.21 is\n\u003e past upstream security support — the floor is a minimum-supported\n\u003e source-compatibility commitment, not the toolchain used to build the tests.\n\u003e CI runs the test suite (with `-race`) on the latest Go. The floor will be\n\u003e bumped when a specific feature requires it.\n\n## 🎯 Quick Start\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"time\"\n\n    \"github.com/bold-minds/dt\"\n)\n\nfunc main() {\n    // ISO in, ISO out (default)\n    fmt.Println(dt.NewDatetime(\"2026-01-15T10:30:00Z\"))\n\n    // Natural-language in, ISO out\n    fmt.Println(dt.NewDatetime(\"Jan 15, 2026\"))\n\n    // Unix seconds in, ISO out\n    fmt.Println(dt.NewDatetime(int64(1736938200)))\n\n    // ISO in, Unix millis out\n    fmt.Println(dt.NewDatetime(\"2026-01-15T10:30:00Z\", dt.FormatAs(dt.Unix())))\n\n    // ISO in, custom format out\n    fmt.Println(dt.NewDatetime(\"2026-01-15T10:30:00Z\", dt.FormatAs(dt.Custom(\"YYYY-MM-DD\"))))\n\n    // With timezone conversion\n    la, _ := time.LoadLocation(\"America/Los_Angeles\")\n    fmt.Println(dt.NewDatetime(\"2026-01-15T18:30:00Z\", dt.ToTimezone(la)))\n\n    // Strip the time component\n    fmt.Println(dt.NewDatetime(\"2026-01-15T10:30:00Z\", dt.DateOnly()))\n\n    // Ordinal day in custom output: \"Jan 15th, 2026\"\n    fmt.Println(dt.NewDatetime(\"2026-01-15T00:00:00Z\",\n        dt.FormatAs(dt.Custom(\"MMM DDD, YYYY\"))))\n}\n```\n\n## 📚 API\n\n### Core\n\n| Function | Purpose |\n|---|---|\n| `NewDatetime(value any, opts ...DatetimeOption) string` | Parse-and-format pipeline. Returns `\"\"` on failure. |\n| `ToDatetime(value string) time.Time` | Parse to `time.Time`. Returns zero time on failure. |\n| `ParseDatetime(value any, expectedFormat, customPattern string) (*DatetimeParseResult, error)` | Parse with format metadata. |\n| `DetectDatetimeFormat(input string) string` | Heuristic format detection. |\n| `FormatDatetime(unixMillis int64, format, customPattern string) (string, error)` | Format a Unix milliseconds value. |\n| `IsValidDatetimeFormat(format string) bool` | Format name validation. |\n| `ParseTimeString(s string) (time.Time, error)` | Thin wrapper around `ToDatetime` returning an explicit error. |\n\n### Output formats\n\n| Constructor | Produces |\n|---|---|\n| `ISO()` | `2006-01-02T15:04:05Z` |\n| `Unix()` | Unix milliseconds as a string |\n| `Custom(pattern)` | Custom pattern — `YYYY`, `MM`, `DD`, `DDD` (ordinal day), `HH`, `hh`, `mm`, `ss` |\n\n### Options\n\n| Option | Effect |\n|---|---|\n| `DateOnly()` | Zero out time components |\n| `TimeOnly()` | Zero out date components |\n| `ToTimezone(tz *time.Location)` | Convert to target timezone before formatting |\n| `FormatAs(format DatetimeFormat)` | Override the default ISO output format |\n\n## 🧭 Supported input layouts\n\n`dt` attempts these layouts in order when parsing a string (first match wins):\n\n- **ISO 8601:** `2006-01-02T15:04:05Z`, `...00.000Z`, `...-07:00`, `...+07:00`\n- **Date-only:** `2006-01-02`\n- **Time-only:** `15:04:05`, `15:04`\n- **Slash/dot/dash dates:** `01/02/2006`, `1/2/2006`, `02/01/2006`, `2/1/2006`, `02.01.2006`, `2.1.2006`, `01-02-2006`, `1-2-2006`\n- **Date-with-time:** `01/02/2006 15:04:05`, `02.01.2006 15:04:05`, `2006-01-02 15:04:05`\n- **Month names:** `Jan 2 2006`, `Jan 2, 2006`, `January 2 2006`, `January 2, 2006`, `2 Jan 2006`, `2 January 2006`\n- **Short year:** `Jan 2 06`, `Jan 2, 06`, `1/2/06`, `01/02/06`, `2/1/06`, `02/01/06`\n- **Unix timestamps** (numeric strings): 10-digit seconds, 13-digit milliseconds\n- **Ordinal days** (`1st`, `2nd`, `3rd`, ...) are stripped before parsing, allowing inputs like `Jan 4th 25`.\n\n## 🔗 Related bold-minds libraries\n\n- [`bold-minds/to`](https://github.com/bold-minds/to) — safe type conversion. Useful when feeding API input through `dt`.\n- [`bold-minds/txt`](https://github.com/bold-minds/txt) — string formatting and manipulation. Pair with `dt.NewDatetime` when composing log or message strings.\n- [`bold-minds/dig`](https://github.com/bold-minds/dig) — nested data navigation. Extract a timestamp field from a deep JSON blob, then pass it to `dt.NewDatetime`.\n\n## 🚫 Non-goals\n\n- **No locale support.** Month names are English-only. Non-English month names will not parse.\n- **No relative-time parsing.** \"yesterday\", \"2 hours ago\", \"next Friday\" are not supported. Use a dedicated library.\n- **No calendar arithmetic.** \"Add 30 days\", \"start of week\", etc. belong in Go's `time` package or a calendar library.\n- **No ambiguity resolution.** If a date is ambiguous between US and European (`01/02/2006`), `dt` picks the first match. If your application is locale-sensitive, parse with an explicit layout via `time.Parse` and skip `dt`.\n- **No timezone database bundling.** `ToTimezone` relies on the caller providing a `*time.Location` from `time.LoadLocation`.\n\n## 📄 License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbold-minds%2Fdt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbold-minds%2Fdt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbold-minds%2Fdt/lists"}