npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@trap_stevo/timetide

v0.0.6

Published

Master the flow of time with the ultimate solution for precision scheduling, real-time synchronization, and temporal control. Designed for developers who demand flexibility and power, this system blends intuitive time parsing, dynamic countdowns, and pers

Readme

⏱️ @trap_stevo/timetide

Master the flow of time with the ultimate solution for precision scheduling, real-time synchronization, and temporal control.
Designed for developers who demand flexibility and power, TimeTide blends intuitive time parsing, dynamic countdowns, persistent task handling, natural-language date interpretation, and nanosecond-to-millennia resolution—all into a seamless, elegant toolkit.

Schedule events using human-readable commands, manage durations with clarity, and broadcast tick events to dashboards or distributed systems. Whether you build responsive interfaces, backend automation, or temporal workflows, TimeTide equips you to orchestrate time itself—with legendary elegance and unmatched control.


🚀 Features

  • ⏱️ Human-readable durations"30m", "1.5h", "2w", "10y", "3gen", "1mil"
  • 📅 Natural-language dates"next Friday", "in 3 days", "end of day", "tomorrow"
  • 🔁 Repeating & persistent timers — recurring jobs that can survive restarts
  • 📦 Named timers — pause, resume, extend, reduce, reschedule, chain follow-ups
  • 📡 Tick streams — global ticks for dashboards, schedulers, analytics
  • 🎯 Threshold comparison helpersexceedsDuration, exceedsTime
  • 🧠 Advanced parsing helpersnormalizeDateInput, parseDateTime
  • 🧮 High-precision units — nanoseconds → millennia
  • ⚙️ Configurable persistence — store timers anywhere

⚙️ Initialization

const TimeTide = require("@trap_stevo/timetide");

TimeTide.initializeTimers({
     persistPath : "./.timers.json",
     disablePersistence : false
});

Initialization Options

| Key | Type | Description | Default | |-----|------|-------------|---------| | persistPath | string | Where persistent timers are stored | "./.timers.json" | | disablePersistence | boolean | Disable reading/writing named timers | false | | onLoadTimersError | function | Called if persisted state cannot be loaded | undefined |


📡 Scheduling API (One-Time & Named Tasks)

Methods

| Method | Description | Persisted? | |--------|-------------|------------| | schedule(name, dur, cb, meta?) | Named timer with persistence | ✔ | | schedule(dur, cb) | Simple one-time timer | ❌ | | countdown(dur, cb) | Alias of schedule(dur, cb) | ❌ | | then(name, cb) | Chain a follow-up after a named timer fires | ✔ | | clear(idOrName) | Cancel timer by ID or name | ✔ | | extend(name, dur) | Add time to a named timer | ✔ | | reduce(name, dur) | Subtract time from a named timer | ✔ | | reschedule(name, dur) | Replace remaining time with new duration | ✔ | | pause(name) | Freeze a named timer and store remaining time | ✔ | | resume(name) | Resume a paused named timer | ✔ | | pauseAll() | Pause all named timers | ✔ | | resumeAll() | Resume all named timers | ✔ |

Example — Named, persistent timer

TimeTide.schedule("backupJob", "45m", () => {
     console.log("Backup finished!");
}, { priority : "high" });

TimeTide.then("backupJob", () => {
     console.log("Follow-up job triggered.");
});

🔁 Recurring Tasks

Non-persistent recurring tasks

| Method | Description | |--------|-------------| | onEvery(interval, cb) | Run a callback every interval | | repeat(interval, cb) | Alias of onEvery |

const id = TimeTide.onEvery("10s", () => {
     console.log("Heartbeat");
});

// Later
TimeTide.clear(id);

Persistent recurring tasks (cron-like loop)

function hourly()
{
     console.log("Hourly job fired");
}

function scheduleHourly()
{
     TimeTide.schedule("hourlyJob", "1h", () => {
          hourly();
          scheduleHourly();
     });
}

scheduleHourly();
  • Recurs forever
  • Can be paused / resumed via pause("hourlyJob") / resume("hourlyJob")
  • Keeps the same named timer

Example — Auto-grading loop (safer pattern)

function autoGrade()
{
     console.log("Auto-grade fired at", new Date().toISOString());
}

function chainAutoGrade()
{
     TimeTide.schedule("auto-grade", "1m", () => {
          try
          {
               autoGrade();
          }
          finally
          {
               // Always re-schedule, even if autoGrade throws
               chainAutoGrade();
          }
     });
}

chainAutoGrade();

📡 Tick Events

| Method | Description | |--------|-------------| | startTick(interval) | Create a global ticker emitting events | | stopTick(interval) | Stop a global ticker | | events.on("tick:interval", cb) | Subscribe to a specific tick label | | events.on("tick", cb) | Subscribe to all ticks, receives label |

TimeTide.startTick("1s");

TimeTide.events.on("tick:1s", () => {
     console.log("Second tick");
});

TimeTide.events.on("tick", (label) => {
     // label could be "1s", "5m", "1000ms", etc.
});

Stop:

TimeTide.stopTick("1s");

⏳ Countdown & Expiration Helpers

| Method | Description | |--------|-------------| | countdown(dur, cb) | One-shot countdown (alias of schedule(dur, cb)) | | expired(date) | true if date is earlier than now | | getTimeUntil(date) | Milliseconds until given date | | addTime(date, dur) | Returns new Date: date + duration | | subtractTime(date, dur) | Returns new Date: date - duration |

Example — Time until a deadline

const deadline = "2025-12-01T17:00:00Z";

const msUntil = TimeTide.getTimeUntil(deadline);
console.log("Remaining:", TimeTide.toReadable(msUntil));

if (TimeTide.expired(deadline))
{
     console.log("Deadline already passed");
}

⚖️ Duration & Time Comparison

exceedsDuration(timeInput, threshold, options?)

Generic threshold comparison between a time and a reference.

Parameters

| Name | Type | Description | |------|------|-------------| | timeInput | Date \| number \| string | Target time to compare | | threshold | number \| string | Milliseconds or duration string ("30m", "1h", "3d", "5y", "2gen", etc.) | | options.reference | Date \| number \| string | Time to compare against (default: now) |

Return

{
     valid : boolean,        // false if inputs could not be parsed
     exceeded : boolean,     // true if |target - reference| > threshold
     diffMs : number | null, // absolute difference in milliseconds
     thresholdMs : number | null
}

Example

const result = TimeTide.exceedsDuration("in 90m", "1h");

if (result.valid && result.exceeded)
{
     console.log("Over 1 hour difference");
}
else if (result.valid)
{
     console.log("Within 1 hour:", TimeTide.toReadable(result.diffMs));
}

exceedsTime(timeInput, threshold, options?)

Alias of exceedsDuration.

const result = TimeTide.exceedsTime(lastPingAt, "30m", { reference : Date.now() });

if (result.exceeded)
{
     console.log("Last ping is older than 30 minutes");
}

Example — Eligibility gate within 1 hour

function inspectEligibility(gradeAtInput)
{
     // gradeAtInput can be Date, ms, numeric string, ISO string, or natural language
     const result = TimeTide.exceedsDuration(gradeAtInput, "1h", { reference : Date.now() });

     if (!result.valid)
     {
          return { eligible : false, reason : "Invalid gradeAt input" };
     }

     if (result.exceeded)
     {
          return {
               eligible : true,
               reason : "Grade time exceeded 1 hour threshold"
          };
     }

     return {
          eligible : false,
          reason : `Still within 1 hour window (${TimeTide.toReadable(result.diffMs)} difference)`
     };
}

🧠 Time Parsing, Conversion & Utilities

All time utilities are provided directly on TimeTide.

| Method | Description | |--------|-------------| | parseDuration(str) | Parse "1h 30m" → ms | | toMilliseconds(str) | Duration string → milliseconds | | toSeconds(str) | Duration string → seconds | | toReadable(ms) | Convert ms to "2h 3m 10s" style string | | toETA(seconds) | Convert seconds (numeric) to a readable ETA string | | parseDate(str) | Parse natural-language / ISO date into Date | | normalizeDateInput(input) | Normalize Date / ms / numeric / string input into Date or null | | parseDateTime(input, unit) | Parse date-like input into a specific time unit | | validDate(input) | Returns true if input can be parsed into a valid date |


parseDateTime(input, unit = "ms")

Convert any supported date-like input into the desired time unit using a unit + alias map that mirrors the duration model.

Supported input types

  • Date
  • millisecond number
  • numeric timestamp string (e.g. "1763754901019")
  • ISO date string
  • natural language ("in 1 hour", "tomorrow", "next Friday 6pm", etc.)

Supported units

| Unit | Aliases | Output | |------|---------|--------| | ms | millisecond, milliseconds | Milliseconds since epoch | | s | sec, second, seconds | Whole seconds since epoch | | m | min, minute, minutes | Whole minutes since epoch | | h | hr, hour, hours | Whole hours since epoch | | d | day, days | Whole days since epoch | | w | week, weeks | Whole weeks since epoch | | mo | month, months | Approx. months since epoch | | y | yr, year, years | Approx. years since epoch | | dec | decade, decades | Approx. decades since epoch | | cen | century, centuries | Approx. centuries since epoch | | gen | generation, generations | Approx. generations since epoch | | mil | millennium, millennia | Approx. millennia since epoch | | iso | — | ISO string | | date | — | Date object |

Internally, parseDateTime:

  1. Normalizes the input into a Date
  2. Converts that Date to milliseconds (ms)
  3. Uses a factor map + alias map to divide into the requested unit
  4. Returns a rounded-down integer for numeric units

Examples

// 1) Millisecond timestamp from ISO string
const ts = TimeTide.parseDateTime("2025-11-21T20:46:59.495Z", "ms");

// 2) Unix-style seconds from natural language
const unix = TimeTide.parseDateTime("next Friday", "seconds"); // "seconds" → "s"

// 3) Days since epoch
const days = TimeTide.parseDateTime("today", "days");

// 4) ISO from natural language
const iso = TimeTide.parseDateTime("in 2 weeks", "iso");

// 5) Using a numeric ms timestamp input and converting to days
const createdAtMs = Date.now() - TimeTide.toMilliseconds("3d 2h");
const ageDays = TimeTide.parseDateTime(createdAtMs, "days");

// ⭐ 6) Raw millisecond timestamp directly from DB / storage
const dbTs = 1763754901019;
const normalized = TimeTide.parseDateTime(dbTs, "ms");
console.log(normalized); // → 1763754901019

// 7) Gating based on a future point in time
const gradeAt = TimeTide.parseDateTime("in 1 hour", "ms");
const remainingMs = gradeAt - Date.now();

console.log("Remaining until grade:", TimeTide.toReadable(remainingMs));

🔥 Supported Duration Units

TimeTide supports mixed & stacked units in parseDuration / toMilliseconds:

"1h 30m"
"2d 4h 20m 5s"
"1.5h"
"3gen 5y 2mo"
"10y 2w 3d 4h 5m 6s"

Unit Table

| Unit | Tokens | Approximate ms | |------|--------|----------------| | Nanoseconds | ns, nanoseconds | 1e-6 | | Milliseconds | ms, milliseconds | 1 | | Seconds | s, seconds | 1000 | | Minutes | m, minutes | 60000 | | Hours | h, hours | 3600000 | | Days | d, days | 86400000 | | Weeks | w, weeks | 604800000 | | Months | mo, months | 2629800000 | | Years | y, years | 31557600000 | | Decades | dec, decades | 315576000000 | | Centuries | cen, centuries | 3155760000000 | | Generations | gen, generations | 788940000000 | | Millennia | mil, millennia | 31557600000000 |


🌙 Natural-Language Date Phrases

Examples of phrases parseDate / parseDateTime can understand include:

  • "now", "today", "tonight"
  • "end of day", "midnight", "noon"
  • "yesterday", "tomorrow"
  • "in 3 hours", "in 5 days", "in 2 weeks"
  • "10 minutes ago", "3 days ago"
  • "next Monday", "last Friday", "this Friday"
  • "this month", "next month", "last year"
  • "next weekend"
  • "January 6, 2025 13:45"
  • "2025-01-06T13:45:00Z"

📦 Installation

npm install @trap_stevo/timetide

⚡ Quick Start (Step-by-Step)

1) Initialize TimeTide

const TimeTide = require("@trap_stevo/timetide");

TimeTide.initializeTimers({
     persistPath : "./.timers.json",
     disablePersistence : false
});

2) Schedule a simple one-time task

TimeTide.schedule("10s", () => {
     console.log("⏰ Fired after 10 seconds");
});

3) Create a named, persistent task

TimeTide.schedule("daily-report", "24h", () => {
     console.log("📊 Daily report generated");
}, { type : "report", priority : "high" });

TimeTide.then("daily-report", () => {
     console.log("✅ Daily report follow-up");
});

If your app restarts and you call initializeTimers again with the same persistPath, daily-report will be restored (as long as it hasn’t fired yet and its callback is registered again).

4) Create a recurring heartbeat

const heartbeatID = TimeTide.onEvery("5s", () => {
     console.log("💓 Heartbeat:", new Date().toISOString());
});

// Later:
TimeTide.clear(heartbeatID);

5) Use natural-language dates and duration comparison

// "next Friday 18:00" as a millisecond timestamp
const launchAtMs = TimeTide.parseDateTime("next Friday 6pm", "ms");
const remainingMs = launchAtMs - Date.now();

console.log("Time until launch:", TimeTide.toReadable(remainingMs));

// Check if something is more than 1 hour away from now
const result = TimeTide.exceedsDuration("in 90m", "1h");

if (result.valid && result.exceeded)
{
     console.log("⏳ More than 1 hour difference");
}

🗂️ Inspect Active Timers

const timers = TimeTide.getTimers();

console.log(timers);
/*
{
     backupJob : {
          createdAt : Date,
          remainingMs : 120000,
          readable : "2m",
          meta : { priority : "high" }
     }
}
*/

🧼 Cleanup Pattern

const id = TimeTide.onEvery("5s", () => {
     console.log("tick");
});

TimeTide.startTick("1m");

function cleanup()
{
     TimeTide.clear(id);
     TimeTide.stopTick("1m");
}

process.on("SIGINT", cleanup);
process.on("SIGTERM", cleanup);

📜 License

See LICENSE.md


⏱️ Control Time. Shape Systems.

From millisecond-precision scheduling to natural-language parsing, from duration comparison to recurring, persistent, restart-safe timers—TimeTide gives you complete command over time itself.