{"id":51676244,"url":"https://github.com/hstern/go-jscalendar","last_synced_at":"2026-07-15T06:30:43.403Z","repository":{"id":366347811,"uuid":"1275942198","full_name":"hstern/go-jscalendar","owner":"hstern","description":"Go library implementing RFC 8984 (JSCalendar: A JSON Representation of Calendar Data)","archived":false,"fork":false,"pushed_at":"2026-06-21T13:48:40.000Z","size":168,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-21T14:06:40.580Z","etag":null,"topics":["calendar","go","golang","icalendar","jscalendar","json","rfc8984"],"latest_commit_sha":null,"homepage":"https://www.rfc-editor.org/rfc/rfc8984.html","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hstern.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-21T10:42:15.000Z","updated_at":"2026-06-21T13:48:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hstern/go-jscalendar","commit_stats":null,"previous_names":["hstern/go-jscalendar"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hstern/go-jscalendar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hstern%2Fgo-jscalendar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hstern%2Fgo-jscalendar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hstern%2Fgo-jscalendar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hstern%2Fgo-jscalendar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hstern","download_url":"https://codeload.github.com/hstern/go-jscalendar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hstern%2Fgo-jscalendar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35494971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-15T02:00:06.706Z","response_time":131,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["calendar","go","golang","icalendar","jscalendar","json","rfc8984"],"created_at":"2026-07-15T06:30:42.687Z","updated_at":"2026-07-15T06:30:43.398Z","avatar_url":"https://github.com/hstern.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-jscalendar\n\n[![CI](https://github.com/hstern/go-jscalendar/actions/workflows/ci.yml/badge.svg)](https://github.com/hstern/go-jscalendar/actions/workflows/ci.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/hstern/go-jscalendar.svg)](https://pkg.go.dev/github.com/hstern/go-jscalendar)\n\nA Go library implementing **[RFC 8984 — JSCalendar: A JSON Representation\nof Calendar Data](https://www.rfc-editor.org/rfc/rfc8984.html)**.\n\nJSCalendar is the JSON-native representation of calendar data — the\nmodern counterpart to iCalendar (RFC 5545). A top-level object is an\n`Event`, a `Task`, or a `Group`, discriminated by its `@type` member,\nwith typed properties for scheduling, recurrence, time zones,\nparticipants, alerts, and localizations. It is richer and less ambiguous\nthan iCalendar exactly where iCalendar is painful: structured recurrence\nrules instead of an opaque `RRULE` string, IANA time zone names plus\nembedded custom zones, and first-class localizations.\n\n```sh\ngo get github.com/hstern/go-jscalendar\n```\n\n```go\nimport \"github.com/hstern/go-jscalendar\"\n```\n\n## Quickstart\n\nAll snippets below are mirrored by runnable `Example` functions\n(`example_test.go` and `ical/example_test.go`), so they compile and\ntheir output is verified by `go test`.\n\n### Parse and marshal\n\n`Parse` routes a top-level object to the concrete type named by its\n`@type` discriminator — `Event`, `Task`, or `Group`. Marshaling emits\n`@type` first and is byte-stable, which keeps round trips deterministic\nfor interop.\n\n```go\nconst src = `{\n  \"@type\": \"Event\",\n  \"uid\": \"a8df3f1e-1c2b-4d5e-9f00-112233445566\",\n  \"title\": \"Team sync\",\n  \"start\": \"2026-07-01T09:00:00\",\n  \"timeZone\": \"America/New_York\",\n  \"duration\": \"PT1H\"\n}`\n\nobj, err := jscalendar.Parse([]byte(src))\nif err != nil {\n\tlog.Fatal(err)\n}\nev := obj.(*jscalendar.Event)\nfmt.Printf(\"%s in %s for %s\\n\", ev.Title, ev.TimeZone, ev.Duration)\n// Team sync in America/New_York for PT1H\n\nout, err := json.Marshal(ev) // \"@type\" first, byte-stable\n// {\"@type\":\"Event\",\"uid\":\"a8df3f1e-...\",\"title\":\"Team sync\",...}\n```\n\n### Validate\n\nDecoding is deliberately lenient (Postel's law). The RFC 8984 §4–§5\nMUSTs are enforced by an opt-in `Validate` pass, which reports each\nviolation as a `*ValidationError` carrying the offending JSON path.\n\n```go\nev := \u0026jscalendar.Event{Title: \"Missing UID\"}\n\nvar verr *jscalendar.ValidationError\nif errors.As(ev.Validate(), \u0026verr) {\n\tfmt.Printf(\"invalid %s\\n\", verr.Property) // invalid uid\n}\n\nev.UID = \"event-1\"\nfmt.Println(ev.Validate() == nil) // true\n```\n\n### Open extensions (the typed-extension pattern)\n\nUnknown members — a vendor extension or a property from a future\nrevision of the spec, indistinguishable on the wire — round-trip\nlosslessly through each type's `Extra` map as `json.RawMessage`. Read\none out with `DecodeJSON` and set one with `EncodeJSON`; nothing is\ndecoded until you ask for it.\n\n```go\n// Read an unknown member into a typed value.\ntype Room struct {\n\tBuilding string `json:\"building\"`\n\tFloor    int    `json:\"floor\"`\n}\nvar r Room\nerr := jscalendar.DecodeJSON(ev.Extra[\"example.com/room\"], \u0026r)\n// errors.Is(err, jscalendar.ErrExtensionAbsent) reports a missing member.\n\n// Set an unknown member.\nraw, _ := jscalendar.EncodeJSON(map[string]string{\"building\": \"HQ\"})\nev.Extra = map[string]json.RawMessage{\"example.com/room\": raw}\n```\n\n### iCalendar conversion\n\niCalendar interop lives in the `jscalendar/ical` sub-package. Importing\nit is what pulls in\n[`emersion/go-ical`](https://github.com/emersion/go-ical); the core\n`jscalendar` package stays standard-library-only, so consumers who never\nneed iCalendar take on no extra dependency.\n\n```go\nimport \"github.com/hstern/go-jscalendar/ical\"\n\n// iCalendar -\u003e JSCalendar\ncal, _ := goical.NewDecoder(r).Decode()\nobjs, err := ical.FromICal(cal) // []any of *jscalendar.Event / *jscalendar.Task\n\n// JSCalendar -\u003e iCalendar\ncal, err = ical.ToICal(ev) // *goical.Calendar; some edges are lossy (see godoc)\n```\n\n## Status\n\n**Pre-publication — under construction toward `v0.1.0`.** The exported\nAPI is not yet stable. The core object model is standard-library-only;\nthe iCalendar conversion lives in the `jscalendar/ical` subpackage and\nis the only part of the module that depends on\n[`emersion/go-ical`](https://github.com/emersion/go-ical).\n\n## Scope\n\nIn scope for `v0.1.0`:\n\n- The typed object model (RFC 8984 §4–§5): `Event`, `Task`, `Group` and\n  their common, scheduling, and recurrence properties.\n- The property value types (§1.4): `LocalDateTime`, `UTCDateTime`,\n  `Duration`, `SignedDuration`, `TimeZoneId`, `Id`, `PatchObject`,\n  `RecurrenceRule`.\n- A byte-stable JSON codec that round-trips unknown members losslessly\n  and emits `@type` first for interop stability.\n- `Validate` for the §4–§5 MUST requirements.\n- iCalendar ⇄ JSCalendar conversion in `jscalendar/ical`.\n\nOut of scope: JMAP transport, and expansion of recurrence rules into\nconcrete occurrences (the library models the rule; expanding a series\nover a window is the caller's job).\n\n## License\n\n[Apache-2.0](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhstern%2Fgo-jscalendar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhstern%2Fgo-jscalendar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhstern%2Fgo-jscalendar/lists"}