a setTimeout for humans (and so much more)


Keywords
timer, lightweight, countdown, setTimeout, milliseconds, npm, npm-package, time
License
MIT
Install
npm install goodtimer@3.4.0

Documentation

Snyk Vulnerabilities for GitHub Repo

goodtimer logo

A setTimeout for humans (and so much more)

goodtimer demo

🧐 About

goodtimer provides a better way implement setTimeout and setInterval by providing a high-level API to easily manipulate countdowns. It does a number of ⭐️good⭐️ things:

  • It self-corrects delays from the event loop, so it's guaranteed to stay in sync with time.
  • It comes with a flexible timeExpression syntax, so you can easily express time in a number of desireable ways.
  • Provides drop-in replacement to setInterval.
  • Can be used in projects like react with npm, or directly in the browser via cdn;

Installation & simple usage

Download using npm

npm i --save goodtimer

And use in your code!

const { Timer } = require('goodtimer');

new Timer('1:00');

Or replace your drifty setIntervals with setGoodInterval ⭐️:

const { setGoodInterval } = require('goodtimer').timeutil;

setGoodInterval(() => console.log("exactly 1 second!"), 1000);

💝 Browser-compatible client-side version now available!

<script src="https://cdn.nickpal.to/goodtimer/goodtimer-3.3.0.js"></script>
<script>
  new goodtimer.Timer('1:00');
</script>

➡️ Read the full API Docs here or read below to get started quickly 🙇


Simple Usage

const yourFn = () => {};
new Timer('1:00', yourFn); // replacement for setTimeout
new Timer('1:00', yourFn, { repeat: true }); // replacement for setInterval


const timer = new Timer('5:00'); // (Five minutes)
timer.pause();         // freezes timer at given time
timer.unpause();       // resumes timer
timer.reset();         // resests to initial value (in this case 5 minutes)
timer.toString()       // returns in UTC-like format ("5:00.000")
// ~ 1 second later ~
timer.fmtTime("%M minutes %s seconds") // -> "4 minutes 59 seconds" (many ways to use!) 
timer.gt('1:00');      // "greater than" -> true
timer.lt('60:00:00');  // "less than (60 hrs)" -> true
timer.equals('6m');    // (6 minutes, alternate notation) -> false

// or use the Time class and skip the controls
const [minute, second] = [new Time('1m'), new Time('1s')];

minute.gt(second)        // -> true
second.equals(':01')     // -> true
minute.equals(second)    // -> false
second.set(minute)       // set to new value
minute.equals(second)    // -> true
minute.toString()        // -> "1:00.000"

// `timeExpressions` are passed to Time or Timer, and can be an
// object, number, array, or string (in multiple formats)
// below are all the ways to write "25 minutes and 500 milliseconds"

new Time('25:00.5'); // string in UTC-like syntax
new Time('25m500ms'); // string with unit annotation
new Time(1500500);  // number for milliseconds
new Time({          // object with full names
    minutes: 25, 
    milliseconds: 500 
});

See the full API spec for many more uses, or read on for simpler ways to get started.

👨‍💻 Getting started with Timer

Timer is an extension of Time, it inherits all methods and properties, and additionally has a "count down" loop and comes with many useful methods you'd expect from a timer. It's the main feature of goodtimer.

Timer's first argument is required, which is a timeExpression, all other arguments are optional. If the last argument is an object, it is assumed to be the timerOptions, which can be used to override default beheivors of the Timer instance

// without timerOptions
new Timer(timeExpression);
new Timer(timeExpression, onTimeoutFn);
new Timer(timeExpression, onTimeoutFn, onIntervalFn);

// with timerOptions
new Timer(timeExpression, timerOptionsObj);
new Timer(timeExpression, onTimeoutFn, timerOptionsObj);
new Timer(timeExpression, onTimeoutFn, onIntervalFn, timerOptionsObj);

goodtimer automatically can tell which format you're trying to use based on the types of the arguments passed.

Callback function with Timer

It will usually be desirable to have a function called when the timer reaches zero. It might also be handy to have a function called on every second (or "tick") of the timer, for example when you need to update a UI element with the new time remaining. onTimeoutFn and onIntervalFn arguments handle this.

// onTimeout example

const timesUp = () => {
    // your code here
    console.log('ding!');
}

new Timer('5:00', timesUp);

// ~ 5 minutes later ~
// "ding!"

In version 3.3.0 and above, both call back functions can access get the timer instance as their first argument. It's especially useful in onIntervalFn arguments (See v3.2.0 docs for previous syntax).

const updateDOM = (timer) => {
    // this function updates the DOM with the time seperated by colons
    // with the smallest unit of time seconsd ('s'). This removes the milliseconds ('.000') at the end.
    document.getElementById('my-timer').innerText = timer.toString('s');
}

new Timer('5:00', timesUp, updateDOM);

If you want to only use an onIntervalFn, and not an onTimeoutFn, you can pass undefined or null as the middle argument. You could alternatively use TimerOptions object to set these (and more).

// both lines have the same effect.

new Timer('5:00', null, updateDOM);
new Timer('5:00', {onInterval: updateDOM});

TimeExpressions

TimeExpressions are various formats of time that goodtimer recognizes. They are passed in many places, such as the constructors for creating Timers and Time, as well as any place where time is being compared or set.

UTC-like string

There are two ways represent a TimeExpression as a string. The first is UTC-like. Colons and the dot are all optional.

00:00:00:00:00.000 <- milliseconds
|  |  |  |  |
|  |  |  |  seconds
|  |  |  minutes
|  |  hours
|  days
years

Units of time are interpreted from right to left. '3:00' is three minutes, '3:00:00' is three hours '3:00:00:00:00' is three years. A number as a string ('3') is the number of seconds, and an empty string is 0.

Milliseconds must be explicitly specified with the dot, and missing numbers places get a 0 appended. .01 is 10 milliseconds (.010), and .1 is 100 millseconds (.100). This makes values like :02.5 behaive the way you'd expect: 2.500 seconds or "two and a half seconds".

unit-notation string.

You can specify each unit of time in a string with their abbreviation, listed below:

  • ms - milliseconds
  • s - seconds
  • m - minutes
  • h - hours
  • d - days
  • y - years

All units are optional. While doing so would be questionable, notations can be out of order. 1d is 1 day (01:00:00:00.000), 1h30m or 30m1h is 1 hour 30 minutes, while 1h30ms (note the s) is 1 hour 30 milliseconds

milliseconds number

Passing a number represents time in milliseconds. 350 produces the same time as thees '350ms' and '.35' string counterparts.

Note 350 and '350' are NOT the same. The number is 350 milliseconds while the string would be 350 seconds.

TimerOptions

Using an object you can provide an alternative way to declare onTimeout and onInterval functions, as well as configuration for additional behavior. The full object properties are show below

const timerOptions = {
    onTimeout: Function, // function to call when timer hits 0.
    onInterval: Function, // function to call on each second (or tick).
    repeat: Boolean | Number, // repeating beheivor after timer hits 0. (see notes)
    startPaused: Boolean, // if the timer should start counting down on creation or not (default false),
    immediateInterval: Boolean, // if the timer should tick once right when it's created (default false)
    interval: Number, // how many seconds before a tick (default 1, updating is uncommon)
    finalInterval: Boolean, // when timer runs out, only run onTimeout (if defined)
                            // otherwise calls onInterval followed by onTimeout.
  
    /* low-level loop control (https://github.com/nickpalenchar/goodtimer/tree/main/docs/setInterval-clearInterval.md) */
    setInterval: Function,
    clearInterval: Function
}

⚠️ Prior to 3.1.0, Timer never called onInterval when the timer reached 0. It now does the opposite by default. for the old behavior, use { finalInterval: false }, for your timerOptions.

Additional notes on options:

  • onTimeout/onInterval - these should replace the functions passed as their own arguments. If you use both, only the functions in TimerOptions will be honored. new Timer('3', functionA, { onTimeout: functionB }) will result in only functionB being called when the timer reaches zero.
  • repeat - Specifically, when the timer reaches zero, if it has a repeat, it will reset back to its initial value and start the countdown again. Any onTimeout function is called before the reset.
    • Pass a number to make it only repeat a given number of times. { repeat: 2 } mean it will repeat twice, and once it reaches zero again, it will stop and be paused at 0.
    • Pass a boolean to make it never or always repeat. { repeat: false } means it never repeats (this is the default), { repeat: true }, means it always repeats. This can also be written as { repeat: 0 } or { repeat: Infinity } for never and always repeating respectively.
  • startPaused - means the timer will be created and paused at its starting time. Any onInterval function will not be called until unpaused. You must unpause it yourself with timer.unpause() or timer.togglePause()
  • immediateInterval - Timer will immediately tick once when starting. new Timer(5:00)

Ways to Get the time

Timer/Time has properties years, days, hours, minutes, seconds to get a specific unit of time. These are always numbers.

const time = new Time('3:35:08.035');

time.milliseconds; // 35
time.seconds; // 8
time.minutes; // 35
time.hours; // 3
time.days; // 0

You can also convert full times to milliseconds with .inMilliseconds().

const time = new Time('3:35:08.035');

time.inMilliseconds(); // -> 12908035

👨‍🔬 Getting Started with Time

Time is Timer without the countdown or callback functionality. Technically, it is the base-class for Timer.

⚠️ Warning: Time is primarily intended to be used by the Timer class, rather than in isolation. As such, it is not as fully functional as it should be. For example, negative values are not supported. Time is still accessible, however, as it can be used for basic time comparisons.

Creating a Time object

Time can be imported from goodtimer. Its constructor only takes a timeExpression. i.e. new Time(timeExpression)

const { Time } = require('goodtimer');

const minute = new Time('1m');
const hour = new Time('1h');

minute.toString(); // -> "01:00.000"
hour.toString();   // -> "01:00:00.000"  

Full list of Time methods.

Below is a demonstration of all Time methods. Remember, all of these methods are also available with Timer.

const minute = new Time('1m');
const hour = new Time('1h');

minute.inMilliseconds(); // -> 60000
minute.toString()        // -> "01:00.000"

minute.gt(hour);         // -> false
minute.gte(hour);        // -> false
minute.lt(hour);         // -> true
minute.lte(hour);        // -> true
minute.equals(hour);     // -> false

minute.set(hour);        // set to new time
minute.equals(hour);     // -> true

👏 Supporters

Stargazers repo roster for goodtimer Forkers repo roster for goodtimer