{"id":13542866,"url":"https://github.com/lorensr/temporal-time-utils","last_synced_at":"2025-08-22T05:40:33.342Z","repository":{"id":45041999,"uuid":"444176795","full_name":"lorensr/temporal-time-utils","owner":"lorensr","description":"This is a library with some reusable functions for Temporal.io TypeScript SDK","archived":false,"fork":false,"pushed_at":"2022-09-09T17:17:47.000Z","size":94,"stargazers_count":19,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-15T09:39:03.760Z","etag":null,"topics":["job-scheduler","nodejs","temporalio","timers"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/temporal-time-utils","language":"TypeScript","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/lorensr.png","metadata":{"files":{"readme":"README.md","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}},"created_at":"2022-01-03T19:29:50.000Z","updated_at":"2024-10-12T11:27:16.000Z","dependencies_parsed_at":"2022-08-25T13:51:27.276Z","dependency_job_id":null,"html_url":"https://github.com/lorensr/temporal-time-utils","commit_stats":null,"previous_names":["sw-yx/temporal-time-utils"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lorensr/temporal-time-utils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lorensr%2Ftemporal-time-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lorensr%2Ftemporal-time-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lorensr%2Ftemporal-time-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lorensr%2Ftemporal-time-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lorensr","download_url":"https://codeload.github.com/lorensr/temporal-time-utils/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lorensr%2Ftemporal-time-utils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270936514,"owners_count":24670948,"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-18T02:00:08.743Z","response_time":89,"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":["job-scheduler","nodejs","temporalio","timers"],"created_at":"2024-08-01T11:00:19.000Z","updated_at":"2025-08-22T05:40:33.296Z","avatar_url":"https://github.com/lorensr.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":["Libraries"],"readme":"# temporal-time-utils\n\nThis is a library with some reusable functions for [Temporal.io TypeScript SDK](https://docs.temporal.io/docs/typescript/introduction):\n\n- `sleepUntil`: sleep to a specific date, instead of by number of milliseconds\n- `UpdatableTimer`: sleep to a specific date, updatable and queryable\n- `ScheduleWorkflow`: *[Deprecated in favor of [Schedules](https://docs.temporal.io/workflows#schedule)]* schedule other workflows by extended cron syntax, with support for jitter, timezone, max invocations, manual triggers, pausing/unpausing, querying future executions, and more.\n\nThis serves as both a utility library and a demonstration of how you can publish reusable Temporal libraries (both for Workflows and Activities).\n\n⚠️ **Note:** This is not an officially supported Temporal library due to the fact that `sleepUntil` and `UpdatableTimer` are not guaranteed to be accurate: the number of milliseconds until the given date is calculated up front, so if any time/date adjustments are made (like changes in timezones, daylight savings, leap seconds), the timer may not fire at the exact correct time.\n\n```ts\nnpm i temporal-time-utils\n```\n\n## `sleepUntil`\n\nThis is a simple drop in replacement for Temporal's `workflow.sleep()` API for when you need to sleep to a specific date rather than a fixed number of milliseconds.\n\n```ts\nimport { sleepUntil } from \"temporal-time-utils\";\n\n// inside workflow function\nsleepUntil(\"30 Sep \" + (new Date().getFullYear() + 1)); // wake up when September ends\nsleepUntil(\"5 Nov 2022 00:12:34 GMT\"); // wake up at specific time and timezone\n\n// optional 2nd arg\nsleepUntil(\"5 Nov 2022 00:12:34 GMT\", specificDateTime); // take control over the \"start\" time in case you need to\n```\n\nThis is a very simple function - under the hood it just uses `date-fns/differenceInMilliseconds` to calculate time difference.\n\nThis is discussed in the docs https://docs.temporal.io/docs/typescript/workflows#sleep\n\n## `UpdatableTimer`\n\n`sleep` only lets you set a fixed time upfront.\n`UpdatableTimer` is a special class that lets you update that while sleeping.\nYou can consider it the next step up from `sleepUntil`.\n\nAfter you instantiate it with an initial datetime to wake up at, it exposes only two APIs: `then()` for you to `await`, and `.deadline` that you can set and get.\n\n```ts\n// example usage inside workflow function\nexport async function countdownWorkflow(initialDeadline: Date): Promise\u003cvoid\u003e {\n  const timer = new UpdatableTimer(initialDeadline);\n  wf.setHandler(\n    setDeadlineSignal,\n    (deadline) =\u003e void (timer.deadline = deadline)\n  ); // send in new deadlines via Signal\n  wf.setHandler(timeLeftQuery, () =\u003e timer.deadline - Date.now()); // get time left via Query\n  await timer; // if you send in a signal with a new time, this timer will resolve earlier!\n  console.log(\"countdown done!\");\n}\n```\n\nThis is discussed in the docs https://docs.temporal.io/docs/typescript/workflows#async-design-patterns.\n\n## `ScheduleWorkflow`\n\nA Workflow that schedules other Workflows.\n\nThis is a premade Workflow that you can register in a Worker and call from a client, to invoke other Workflows on a schedule. You can consider this the next step up from \"Cron Workflows\".\n\nSee example usage inside of `/apps/fixture`:\n\n- https://github.com/lorensr/temporal-time-utils/blob/main/apps/fixture/src/client.ts invoke the `ScheduleWorkflow` and pass in an `example` Workflow to call on a schedule\n- https://github.com/lorensr/temporal-time-utils/blob/main/apps/fixture/src/workflows.ts#L5 necessary export for Worker to pick it up\n\n```ts\n// inside client file\nasync function run() {\n  const client = new WorkflowClient();\n  const handle = await client.start(ScheduleWorkflow, {\n    args: [\n      \"exampleWorkflow\", // workflow to be executed on a schedule. must be string name.\n      {\n        args: [\"Example arg payload\"], // static for now, but possible to modify to make dynamic in future - ask swyx\n        // // regular workflow options apply here, with two additions (defaults shown):\n        // cancellationType: ChildWorkflowCancellationType.WAIT_CANCELLATION_COMPLETED,\n        // parentClosePolicy: ParentClosePolicy.PARENT_CLOSE_POLICY_TERMINATE\n      },\n      {\n        // args\n        cronParser: {\n          expression: \"* * * * *\", // every minute\n          // options: https://www.npmjs.com/package/cron-parser#user-content-options\n        },\n        // maxInvocations?: number;\n        // jitterMs?: number;\n      },\n    ],\n    taskQueue: \"tutorial\",\n    workflowId: \"my-schedule-id\",\n  });\n}\n```\n\nThis uses https://www.npmjs.com/package/cron-parser under the hood, thereby getting support for things like timezones and \"last of the week\" extensions to the cron syntax:\n\n```ts\n// client.ts\nconst handle = await client.start(ScheduleWorkflow, {\n  args: [\n    \"exampleWorkflow\", // as above\n    {}, // if no args needed\n    {\n      // scheduleOptions\n      cronParser: {\n        expression: \"0 0 * * * 1,3L\", // run every Monday as well as the last Wednesday of the month\n        options: {\n          currentDate: \"2016-03-27 00:00:01\",\n          endDate: new Date(\"Wed, 26 Dec 2012 14:40:00 UTC\"),\n          tz: \"Europe/Athens\",\n        },\n      },\n      maxInvocations: 500,\n      jitterMs: 1000,\n    },\n  ],\n  taskQueue: \"scheduler\",\n  workflowId: \"schedule-for-\" + userId,\n});\n```\n\nThe Workflow exposes a number of useful queries and signals:\n\n```ts\nimport {\n  numInvocationsQuery,\n  futureScheduleQuery,\n  manualTriggerSignal,\n  ScheduleWorkflowState,\n  stateSignal,\n  stateQuery,\n  // ...\n} from \"temporal-time-utils\";\n\nawait handle.query(numInvocationsQuery); // get how many times exampleWorkflow has been invoked by ScheduleWorkflow\nawait handle.query(futureScheduleQuery, 3); // get the next 3 times it is set to be invoked. defaults to 5\nawait handle.signal(manualTriggerSignal); // manually trigger workflow\nawait handle.signal(stateSignal, \"PAUSED\" as ScheduleWorkflowState); // pause workflow\nawait handle.signal(stateSignal, \"RUNNING\" as ScheduleWorkflowState); // resume workflow\nawait handle.cancel(); // stop schedule workflow completely\nawait handle.query(stateQuery); // get wf state (running, paused, or stopped)\n```\n\nThis is a decoupled and slightly modified variant of what was discussed in the docs: https://docs.temporal.io/docs/typescript/workflows#schedule-workflow-example\n\n## Monorepo details\n\nThis project is bootstrapped with https://turborepo.org/.\n\n### Build\n\nTo build all apps and packages, run the following command:\n\n```\ncd my-turborepo\nnpm run build\n```\n\n### Develop\n\nTo develop all apps and packages, run the following command:\n\n```\ncd my-turborepo\nnpm run dev\n```\n\n### Remote Caching\n\nTurborepo can use a technique known as [Remote Caching (Beta)](https://turborepo.org/docs/features/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines.\n\n```\ncd my-turborepo\nnpx turbo login\nnpx turbo link\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Florensr%2Ftemporal-time-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Florensr%2Ftemporal-time-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Florensr%2Ftemporal-time-utils/lists"}