{"id":25765381,"url":"https://github.com/rr0/time","last_synced_at":"2025-08-01T19:32:42.050Z","repository":{"id":256369972,"uuid":"855055445","full_name":"RR0/time","owner":"RR0","description":"EDTF parsing and programmatic API","archived":false,"fork":false,"pushed_at":"2025-05-02T13:48:25.000Z","size":311,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-01T23:36:22.828Z","etag":null,"topics":["date","edtf","iso-8601","parsing","time"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RR0.png","metadata":{"files":{"readme":"README-ts.test.ts","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2024-09-10T08:21:01.000Z","updated_at":"2025-06-21T16:53:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"d80dcd99-b5e1-43cf-8b30-8421967261cf","html_url":"https://github.com/RR0/time","commit_stats":null,"previous_names":["rr0/time"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/RR0/time","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RR0%2Ftime","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RR0%2Ftime/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RR0%2Ftime/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RR0%2Ftime/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RR0","download_url":"https://codeload.github.com/RR0/time/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RR0%2Ftime/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268286398,"owners_count":24225988,"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","status":"online","status_checked_at":"2025-08-01T02:00:08.611Z","response_time":67,"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":["date","edtf","iso-8601","parsing","time"],"created_at":"2025-02-26T22:18:29.889Z","updated_at":"2025-08-01T19:32:42.038Z","avatar_url":"https://github.com/RR0.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"import { describe, test } from \"node:test\"\nimport assert, { fail } from \"node:assert\"\n\nimport { Level2Date as EdtfDate } from \"./src/level2/date/index.mjs\"\nimport { Level2Interval, Level2Interval as EdtfInterval } from \"./src/level2/interval/index.mjs\"\n\nimport { Level2Duration as Duration } from \"./src/level2/duration/index.mjs\"\nimport { level0Calendar } from \"./src/calendar/index.mjs\"\nimport { assertLevel2 } from \"./src/level2/component/Level2TestUtil.mjs\"\nimport { level2Calendar } from \"./src/level2/Level2Calendar.mjs\"\n\ndescribe(\"Demo samples\", () =\u003e {\n\n  describe(\"Dates\", () =\u003e {\n\n    describe(\"instanciation\", () =\u003e {\n\n      test(\"now\", () =\u003e {\n        const now = new EdtfDate()\n        assert.ok(now.year.value \u003e= 2025)\n      })\n\n      test(\"from date\", () =\u003e {\n        const now = EdtfDate.fromDate(new Date(2025, 1, 28))\n        assert.ok(now instanceof EdtfDate)\n        assert.equal(now.year.value, 2025)\n        assert.equal(now.month.value, 2)\n        assert.equal(now.day.value, 28)\n        assert.equal(now.hour?.value, 0)\n        assert.equal(now.minute?.value, 0)\n        assert.equal(now.second?.value, 0)\n      })\n\n      test(\"instanciation\", () =\u003e {\n        const date = new EdtfDate({year: 1972, month: 8, day: 12, hour: 16, minute: 45, second: 55})\n        assert.equal(date.year.value, 1972)\n        assert.equal(date.month.value, 8)\n        assert.equal(date.day.value, 12)\n        assert.equal(date.hour.value, 16)\n        assert.equal(date.minute.value, 45)\n        assert.equal(date.second.value, 55)\n      })\n    })\n\n    test(\"comparison\", () =\u003e {\n      const maybeAugust = EdtfDate.fromString(\"2024-?08-15\")\n      const aroundMarch2025 = EdtfDate.fromString(\"2025-03~\")\n      assert.ok(!maybeAugust.isEqual(aroundMarch2025))\n      assert.ok(maybeAugust.isBefore(aroundMarch2025))\n      assert.ok(aroundMarch2025.isAfter(maybeAugust))\n      const delta = aroundMarch2025.delta(maybeAugust).toSpec()\n      assert.equal(delta.months, 6)\n      assert.equal(delta.days, 16)\n    })\n\n    test(\"uncertain\", () =\u003e {\n      const maybeAugust = EdtfDate.fromString(\"2024-?08-25\")\n      assert.equal(maybeAugust.month.value, 8)\n      assert.equal(maybeAugust.month.uncertainComponent, true)\n      assert.equal(maybeAugust.year.uncertain, true)\n      assert.equal(maybeAugust.year.uncertainComponent, false)\n      assert.equal(maybeAugust.uncertain, true)\n    })\n\n    test(\"approximate\", () =\u003e {\n      const aroundMarch2025 = EdtfDate.fromString(\"2025-03~\")\n      assert.equal(aroundMarch2025.month.approximate, true)\n      assert.equal(aroundMarch2025.month.value, 3)\n      assert.equal(aroundMarch2025.year.approximate, true)\n      assert.equal(aroundMarch2025.year.value, 2025)\n      assert.equal(aroundMarch2025.year.approximate, true)\n      assert.equal(aroundMarch2025.approximate, true)\n    })\n  })\n\n  describe(\"Durations\", () =\u003e {\n\n    test(\"parsing\", () =\u003e {\n      const aroundTenMinutes = Duration.fromString(\"P10M~\")\n      assert.equal(aroundTenMinutes.value, 10 * level0Calendar.minute.duration)\n      const tenMnSpec = aroundTenMinutes.toSpec()\n      assert.equal(tenMnSpec.minutes, 10)\n    })\n\n    test(\"between\", () =\u003e {\n      const start = EdtfDate.fromString(\"2024-01-01\")\n      const now = new EdtfDate()\n      const duration = Duration.between(start, now)\n      assert.ok(duration.toSpec().years.value \u003e= 1)\n    })\n  })\n\n  describe(\"Intervals\", () =\u003e {\n\n    test(\"instanciation\", () =\u003e {\n      const start = new EdtfDate({year: 1972, month: 8, day: 12, hour: 16, minute: 45, second: 55})\n      const end = new EdtfDate({year: 1972, month: 8, day: 12, hour: 16, minute: 45, second: 55})\n      const interval = new Level2Interval(start, end)\n      assert.equal(interval.start.year.value, 1972)\n      assert.equal(interval.start.month.value, 8)\n      assert.equal(interval.start.day.value, 12)\n      assert.equal(interval.start.hour.value, 16)\n      assert.equal(interval.start.minute.value, 45)\n      assert.equal(interval.start.second.value, 55)\n    })\n\n\n    test(\"from uncertain to approximate\", {todo: true}, () =\u003e {\n      const maybeAugust = EdtfInterval.fromString(\"2023-12-?08/2024-12~\")\n      assertLevel2(maybeAugust.start.day).to.equal(8).and.beUncertain().atTheComponentLevel().but.bePrecise()\n      assertLevel2(maybeAugust.end.month).to.equal(\n        12).and.beApproximate().atTheGroupLevel().but.beApproximate().atTheGroupLevel()\n    })\n\n    test(\"approximate\", () =\u003e {\n      const aroundMarch2025 = EdtfDate.fromString(\"2025-03~\")\n      assertLevel2(aroundMarch2025.month).to.equal(3).and.beApproximate().atTheGroupLevel().but.not.beUncertain()\n      assertLevel2(aroundMarch2025.year).to.equal(2025).and.beApproximate().atTheGroupLevel().but.not.beUncertain()\n      assert.equal(aroundMarch2025.approximate, true)\n    })\n  })\n\n  describe(\"prev\", () =\u003e {\n\n    test(\"valid\", () =\u003e {\n      const dateWithYear = EdtfDate.fromString(\"1985\")\n      const nextDateWithYear = dateWithYear.previous()\n      assert.equal(nextDateWithYear.toString(), \"1984\")\n\n      const dateWithMonth = EdtfDate.fromString(\"1985-07\")\n      const nextDateWithMonth = dateWithMonth.previous()\n      assert.equal(nextDateWithMonth.toString(), \"1985-06\")\n\n      const dateWithDay = EdtfDate.fromString(\"1985-07-25\")\n      const nextDateWithDay = dateWithDay.previous()\n      assert.equal(nextDateWithDay.toString(), \"1985-07-24\")\n\n      const dateWithHour = EdtfDate.fromString(\"1985-07-25 16:00\")\n      const nextDateWithHour = dateWithHour.previous()\n      assert.equal(nextDateWithHour.toString(), \"1985-07-25T15:00\")\n\n      const dateWithMinute = EdtfDate.fromString(\"1985-07-25 16:30\")\n      const nextDateWithMinute = dateWithMinute.previous()\n      assert.equal(nextDateWithMinute.toString(), \"1985-07-25T16:29\")\n\n      const dateWithSecond = EdtfDate.fromString(\"1985-07-25 16:30:40\")\n      const nextDateWithSecond = dateWithSecond.previous()\n      assert.equal(nextDateWithSecond.toString(), \"1985-07-25T16:30:39\")\n    })\n\n    test(\"overflow\", () =\u003e {\n      const date = EdtfDate.fromString(level2Calendar.year.min.toString())\n      try {\n        date.previous()\n        fail(\"Should not allow next year before min\")\n      } catch (e) {\n        assert.equal(e.message,\n          \"year value must be \u003e= -9007199254740991 and \u003c= 9007199254740991, but was -9007199254740992\")\n      }\n    })\n  })\n\n  describe(\"next\", () =\u003e {\n\n    test(\"valid\", () =\u003e {\n      const date = EdtfDate.fromString(\"1985\")\n      const next = date.next()\n      assert.equal(next.toString(), \"1986\")\n\n      const dateWithMonth = EdtfDate.fromString(\"1985-07\")\n      const nextDateWithMonth = dateWithMonth.next()\n      assert.equal(nextDateWithMonth.toString(), \"1985-08\")\n\n      const dateWithDay = EdtfDate.fromString(\"1985-07-25\")\n      const nextDateWithDay = dateWithDay.next()\n      assert.equal(nextDateWithDay.toString(), \"1985-07-26\")\n\n      const dateWithHour = EdtfDate.fromString(\"1985-07-25T16:00\")\n      dateWithHour.minute = undefined\n      const nextDateWithHour = dateWithHour.next()\n      assert.equal(nextDateWithHour.toString(), \"1985-07-25T17\")\n\n      const dateWithMinute = EdtfDate.fromString(\"1985-07-25 16:30\")\n      const nextDateWithMinute = dateWithMinute.next()\n      assert.equal(nextDateWithMinute.toString(), \"1985-07-25T16:31\")\n\n      const dateWithSecond = EdtfDate.fromString(\"1985-07-25 16:30:40\")\n      const nextDateWithSecond = dateWithSecond.next()\n      assert.equal(nextDateWithSecond.toString(), \"1985-07-25T16:30:41\")\n    })\n\n    test(\"overflow\", () =\u003e {\n      const certainYear = EdtfDate.fromString(String(level2Calendar.year.max))\n      try {\n        certainYear.next()\n        fail(\"Should not allow next year after max\")\n      } catch (e) {\n        assert.equal(e.message,\n          \"year value must be \u003e= -9007199254740991 and \u003c= 9007199254740991, but was 9007199254740992\")\n      }\n    })\n  })\n})\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frr0%2Ftime","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frr0%2Ftime","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frr0%2Ftime/lists"}