Giter Club home page Giter Club logo

countdownjs's Introduction

A simple JavaScript API for producing an accurate, intuitive description of the timespan between two Date instances.


The Motivation

While seemingly a trivial problem, the human descriptions for a span of time tend to be fuzzier than a computer naturally computes. More specifically, months are an inherently messed up unit of time. For instance, when a human says "in 1 month" how long do they mean? Banks often interpret this as thirty days but that is only correct one third of the time. People casually talk about a month being four weeks long but there is only one month in a year which is four weeks long and it is only that long about three quarters of the time. Even intuitively defining these terms can be problematic. For instance, what is the date one month after January 31st, 2001? JavaScript will happily call this March 3rd, 2001. Humans will typically debate either February 28th, 2001 or March 1st, 2001. It seems there isn't a "right" answer, per se.

The Algorithm

Countdown.js emphasizes producing intuitively correct description of timespans which are consistent as time goes on. To do this, Countdown.js uses the concept of "today's date next month" to mean "a month from now". As the days go by, Countdown.js produces consecutively increasing or decreasing counts without inconsistent jumps. The range of accuracy is only limited by the underlying system clock.

Countdown.js approaches finding the difference between two times like an elementary school subtraction problem. Each unit acts like a base-10 place where any overflow is carried to the next highest unit, and any underflow is borrowed from the next highest unit. In base-10 subtraction, every column is worth 10 times the previous column. With time, it is a little more complex since the conversions between the units of time are not the same and months are an inconsistent number of days. Internally, Countdown.js maintains the concept of a "reference month" which determines how many days a given month or year represents. In the final step of the algorithm, Countdown.js then prunes the set of time units down to only those requested, forcing larger units down to smaller.

Time Zones & Daylight Savings Time

As of v2.4, Countdown.js performs all calculations with respect to the viewer's local time zone. Earlier versions performed difference calculations in UTC, which is generally the correct way to do math on time. In this situation, however, an issue with using UTC happens when either of the two dates being worked with is within one time zone offset of a month boundary. If the UTC interpretation of that instant in time is in a different month than that of the local time zone, then the viewer's perception is that the calculated time span is incorrect. This is the heart of the problem that Countdown.js attempts to solve: talking about spans of time can be ambiguous. Nearly all bugs reported for Countdown.js have been because the viewer expects something different due to their particular time zone.

JavaScript (ECMA-262) only works with dates as UTC or the local time zone, not arbitrary time zones. By design, all JS Date objects represent an instant in time (milliseconds since midnight Jan 1, 1970 in UTC) interpreted as the user's local time. Since most humans think about local time not UTC, it the most makes sense to perform this time span algorithm in reference to local time.

Daylight Savings Time further complicates things, creating hours which get repeated and hours which cannot exist. Countdown.js effectively ignores these edge cases and talks about time preferring human intuition about time over surprise exactness. Example: A viewer asks for the description from noon the day before a daylight savings begins to noon the day after. A computer would answer "23 hours" whereas a human would confidently answer "1 day" even after being reminded to "Spring Forward". The computer is technically more accurate but this is not the value that humans actually expect or desire. Humans pretend that time is simple and makes sense. Unfortunately, humans made time far more complex than it needed to be with time zones and daylight savings. UTC simplifies time but at the cost of being inconsistent with human experience.


The API

A simple but flexible API is the goal of Countdown.js. There is one global function with a set of static constants:

var timespan = countdown(start|callback, end|callback, units, max, digits);

The parameters are a starting Date, ending Date, an optional set of units, an optional maximum number of units, and an optional maximum number of decimal places on the smallest unit. units defaults to countdown.DEFAULTS, max defaults to NaN (all specified units), digits defaults to 0.

countdown.ALL =
	countdown.MILLENNIA |
	countdown.CENTURIES |
	countdown.DECADES |
	countdown.YEARS |
	countdown.MONTHS |
	countdown.WEEKS |
	countdown.DAYS |
	countdown.HOURS |
	countdown.MINUTES |
	countdown.SECONDS |
	countdown.MILLISECONDS;

countdown.DEFAULTS =
	countdown.YEARS |
	countdown.MONTHS |
	countdown.DAYS |
	countdown.HOURS |
	countdown.MINUTES |
	countdown.SECONDS;

This allows a very minimal call to accept the defaults and get the time since/until a single date. For example:

countdown( new Date(2000, 0, 1) ).toString();

This will produce a human readable description like:

11 years, 8 months, 4 days, 10 hours, 12 minutes and 43 seconds

The start / end arguments

The parameters start and end can be one of several values:

  1. null which indicates "now".
  2. a JavaScript Date object.
  3. a number specifying the number of milliseconds since midnight Jan 1, 1970 UTC (i.e., the "UNIX epoch").
  4. a callback function accepting one timespan argument.

To reference a specific instant in time, either use a number offset from the epoch, or a JavaScript Date object instantiated with the specific offset from the epoch. In JavaScript, if a Date object is instantiated using year/month/date/etc values, then those values are interpreted interpreted in reference to the browser's local time zone and daylight savings settings.

If start and end are both specified, then repeated calls to countdown(...) will always return the same result. If one date argument is left null while the other is provided, then repeated calls will count up if the provided date is in the past, and it will count down if the provided date is in the future. For example,

var daysSinceLastWorkplaceAccident = countdown(507314280000, null, countdown.DAYS);

If a callback function is supplied, then an interval timer will be started with a frequency based upon the smallest unit (e.g., if countdown.SECONDS is the smallest unit, the callback will be invoked once per second). Rather than returning a Timespan object, the timer's ID will be returned to allow canceling by passing into window.clearInterval(id). For example, to show a timer since the page first loaded:

var timerId =
  countdown(
    new Date(),
    function(ts) {
      document.getElementById('pageTimer').innerHTML = ts.toHTML("strong");
    },
    countdown.HOURS|countdown.MINUTES|countdown.SECONDS);

// later on this timer may be stopped
window.clearInterval(timerId);

The units argument

The static units constants can be combined using standard bitwise operators. For example, to explicitly include "months or days" use bitwise-OR:

countdown.MONTHS | countdown.DAYS

To explicitly exclude units like "not weeks and not milliseconds" combine bitwise-NOT and bitwise-AND:

~countdown.WEEKS & ~countdown.MILLISECONDS

Equivalently, to specify everything but "not weeks or milliseconds" wrap bitwise-NOT around bitwise-OR:

~(countdown.WEEKS | countdown.MILLISECONDS)

The max argument

The next optional argument max specifies a maximum number of unit labels to display. This allows specifying which units are interesting but only displaying the max most significant units.

countdown(start, end, units).toString() => "5 years, 1 month, 19 days, 12 hours and 17 minutes"

Specifying max as 2 ensures that only the two most significant units are displayed (note the rounding of the least significant unit):

countdown(start, end, units, 2).toString() => "5 years and 2 months"

Negative or zero values of max are ignored.


Breaking change in v2.3.0!

Previously, the max number of unit labels argument used to be specified when formatting in timespan.toString(...) and timespan.toHTML(...). v2.3.0 moves it to countdown(...), which improves efficiency as well as enabling fractional units (see below).


The digits argument

The final optional argument digits allows fractional values on the smallest unit.

countdown(start, end, units, max).toString() => "5 years and 2 months"

Specifying digits as 2 allows up to 2 digits beyond the decimal point to be displayed (note the rounding of the least significant unit):

countdown(start, end, units, max, 2).toString() => "5 years and 1.65 months"

digits must be between 0 and 20, inclusive.


Rounding

With the calculations of fractional units in v2.3.0, the smallest displayed unit now properly rounds. Previously, the equivalent of "1.99 years" would be truncated to "1 year", as of v2.3.0 it will display as "2 years".

Typically, this is the intended interpretation but there are a few circumstances where people expect the truncated behavior. For example, people often talk about their age as the lowest possible interpretation. e.g., they claim "39-years-old" right up until the morning of their 40th birthday (some people do even for years after!). In these cases, after calling countdown(start,end,units,max,20) with the largest possible number of digits, you might want to set ts.years = Math.floor(ts.years) before calling ts.toString(). The vain might want you to set ts.years = Math.min(ts.years, 39)!


Timespan result

The return value is a Timespan object which always contains the following fields:

  • Date start: the starting date object used for the calculation
  • Date end: the ending date object used for the calculation
  • Number units: the units specified
  • Number value: total milliseconds difference (i.e., end - start). If end < start then value will be negative.

Typically the end occurs after start, but if the arguments were reversed, the only difference is Timespan.value will be negative. The sign of value can be used to determine if the event occurs in the future or in the past.

The following time unit fields are only present if their corresponding units were requested:

  • Number millennia
  • Number centuries
  • Number decades
  • Number years
  • Number months
  • Number days
  • Number hours
  • Number minutes
  • Number seconds
  • Number milliseconds

Finally, Timespan has two formatting methods each with some optional parameters. If the difference between start and end is less than the requested granularity of units, then toString(...) and toHTML(...) will return the empty label (defaults to an empty string).

String toString(emptyLabel): formats the Timespan object as an English sentence. e.g., using the same input:

ts.toString() => "5 years, 1 month, 19 days, 12 hours and 17 minutes"

String toHTML(tagName, emptyLabel): formats the Timespan object as an English sentence, with the specified HTML tag wrapped around each unit. If no tag name is provided, "span" is used. e.g., using the same input:

ts.toHTML() => "<span>5 years</span>, <span>1 month</span>, <span>19 days</span>, <span>12 hours</span> and <span>17 minutes</span>"

ts.toHTML("em") => "<em>5 years</em>, <em>1 month</em>, <em>19 days</em>, <em>12 hours</em> and <em>17 minutes</em>"

Localization

Very basic localization is supported via the static setLabels and resetLabels methods. These change the functionality for all timespans on the page.

countdown.resetLabels();

countdown.setLabels(singular, plural, last, delim, empty, formatter);

The arguments:

  • singular is a pipe ('|') delimited ascending list of singular unit name overrides
  • plural is a pipe ('|') delimited ascending list of plural unit name overrides
  • last is a delimiter before the last unit (default: ' and ')
  • delim is a delimiter to use between all other units (default: ', '),
  • empty is a label to use when all units are zero (default: '')
  • formatter is a function which takes a number and returns a string (default uses Number.toString()),
    allowing customization of the way numbers are formatted, e.g., commas every 3 digits or some unique style that is specific to your locale.

Notice that the spacing is part of the labels.

The following examples would translate the output into Brazilian Portuguese and French, respectively:

countdown.setLabels(
	' milissegundo| segundo| minuto| hora| dia| semana| mês| ano| década| século| milênio',
	' milissegundos| segundos| minutos| horas| dias| semanas| meses| anos| décadas| séculos| milênios',
	' e ',
	' + ',
	'agora');

countdown.setLabels(
	' milliseconde| seconde| minute| heure| jour| semaine| mois| année| décennie| siècle| millénaire',
	' millisecondes| secondes| minutes| heures| jours| semaines| mois| années| décennies| siècles| millénaires',
	' et ',
	', ',
	'maintenant');

If you only wanted to override some of the labels just leave the other pipe-delimited places empty. Similarly, leave off any of the delimiter arguments which do not need overriding.

countdown.setLabels(
	'||| hr| d',
	'ms| sec|||| wks|| yrs',
	', and finally ');

ts.toString() => "1 millennium, 2 centuries, 5 yrs, 1 month, 7 wks, 19 days, 1 hr, 2 minutes, 17 sec, and finally 1 millisecond"

If you only wanted to override the empty label:

countdown.setLabels(
	null,
	null,
	null,
	null,
	'Now.');

ts.toString() => "Now."

The following would be effectively the same as calling countdown.resetLabels():

countdown.setLabels(
	' millisecond| second| minute| hour| day| week| month| year| decade| century| millennium',
	' milliseconds| seconds| minutes| hours| days| weeks| months| years| decades| centuries| millennia',
	' and ',
	', ',
	'',
	function(n){ return n.toString(); });

License

Distributed under the terms of The MIT license.


Copyright (c) 2006-2014 Stephen M. McKamey

countdownjs's People

Contributors

eduardo-matos avatar jiaming10 avatar matheusmatos avatar mckamey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

countdownjs's Issues

Display days looks strange for dates in Febuary

countdown(Date.UTC(2018,1,12,20,45)) will produce something like 11 months, 27 days, ... at this particular moment. It will roll over to 1 year when the date rolls over. I believe that in this instance the days from the previous month should be used, not the current one. Very specifically, I would like to see the following unit tests added:

test('February day of month', function() {
	var input = countdown(Date.UTC(2018,1,6,20,45),Date.UTC(2019,1,5,20,45));
	var expected = '11 months and 30 days';
	var actual = input.toString();
	countdown.resetFormat();
	same(actual, expected, '');
});

test('January day of month', function() {
	var input = countdown(Date.UTC(2018,0,6,20,45),Date.UTC(2019,0,5,20,45));
	var expected = '11 months and 30 days';
	var actual = input.toString();
	countdown.resetFormat();
	same(actual, expected, '');
});

test('December day of month', function() {
	var input = countdown(Date.UTC(2018,11,6,20,45),Date.UTC(2019,11,5,20,45));
	var expected = '11 months and 29 days';
	var actual = input.toString();
	countdown.resetFormat();
	same(actual, expected, '');
});

test('February 28 Jan 31 of month', function() {
	var input = countdown(Date.UTC(2018,1,28,20,45),Date.UTC(2019,0,31,20,45));
	var expected = '11 months and 3 days';
	var actual = input.toString();
	countdown.resetFormat();
	same(actual, expected, '');
});

test('February 28  Feb 1 day of month', function() {
	var input = countdown(Date.UTC(2018,1,28,20,45),Date.UTC(2019,1,1,20,45));
	var expected = '11 months and 4 days';
	var actual = input.toString();
	countdown.resetFormat();
	same(actual, expected, '');
});

Currently only the Feb 28 Jan 31 and January test pass, the others fail. This isn't a trivial problem to fix, from what I have been able to do so far, but I will look in to it myself as well.

wrong count 1 more month is added

Hello ;-) I am counting down from today (20 february 2024) till 14 september 2024 at 11:00 but the result it is:
7 MONTHS, 22 DAYS, 11 HOURS, 10 MINUTES

but the correct one should be:
6 MONTHS, 22 DAYS, 11 HOURS, 10 MINUTES

countdown( new Date(2024, 9, 14, 11), function(ts) { document.getElementById('days').innerHTML = ts.toString(); }, countdown.YEARS|countdown.MONTHS|countdown.DAYS|countdown.HOURS|countdown.MINUTES|countdown.SECONDS);

even changing to days:
countdown.DAYS|countdown.HOURS|countdown.MINUTES|countdown.SECONDS it give back
236 DAYS, 11 HOURS, 6 MINUTES
instead of
206 DAYS, 11 HOURS, 6 MINUTES

When specifying duration directly, allow floating numbers

I would like to be able to do something like this (how many hours are left until 1.5 years from now):
countdown(null, { years: 1.5 }, countdown.HOURS).hours

Currently the fraction component is ignored, and it is the same as:
countdown(null, { years: 1 }, countdown.HOURS).hours

Use no labels

I want to use a time format like this

12:34:56 /* hours:minutes:seconds */

So I can only do this by overriding it by blank spaces like this

countdown.setLabels(
    ' | | | | | | | | | | ',
    ' | | | | | | | | | | ',
    ':',
    ':',
    null);

Because if I would use '||||||||||' (without blank spaces) the script would think I don't want to override. But now I have an output with blank spaces like this

12 :34 :56

How can I remove the blank spaces (without a JavaScript string replace workaround)?

Migrate to ES6 export

The modern build tooling, browsers, and Nodejs support ES6 import/export.

May you migrate to ES6 export instead of a hacky way to detect the environment

export { countdown };

Add support for Web Workers

We can't use this library into Web Worker because we don't have any module.exports nor window.

We have en error:

ReferenceError: window is not defined

Here:

countdownjs/countdown.js

Lines 1355 to 1364 in cb5b187

if (module && module.exports) {
module.exports = countdown;
} else if (typeof window.define === 'function' && typeof window.define.amd !== 'undefined') {
window.define('countdown', [], function() {
return countdown;
});
}
return countdown;

Suggestion of fix.

Add check for window object

if (typeof module !== 'undefined' && module.exports) {
  module.exports = countdown;

- } else if (typeof window.define === 'function' && typeof window.define.amd !== 'undefined') { 
+ } else if (typeof window !== 'undefined' && typeof window.define === 'function' && typeof window.define.amd !== 'undefined') {
   window.define('countdown', [], function() {
    return countdown;
  });
}

Leading zeros

With regard to #4, output with leading zeros would be very handy.

What to put in html?

Why dont you write what to put in the html code?

Uncaught TypeError: countdown is not a function

Is it possible .toHTML("tag","class")?

Hi,

Thank you for this awesome library!

I am wondering if possible to format the result like:

countdown(start,end,units,max,digits).toHTML("button", "classname") ?

button.btn btn-warning

then if the start now <= countdown.MONTHS .toHTML("button","btn btn-danger")

or I should write a custom function for it?

Thanks,

React Native

hey
this project support react native?
can i import this function to react native project?

thanks

Improve localization interface

Issue migrated from Bitbucket...

Currently the localization interface is a bunch of parameters on setLabels(...) and a parameterless resetLabels(). That whole method is getting a bit long and convoluted as it organically grew without much forethought.

This task is to clean it up by creating a new method accepting a general Format object which contains all those features. It will make it easier than remembering how many nulls to put before the value you actually want to set.

The current method looks like:

  countdown.setLabels(singular, plural, last, delim, empty, formatter);

Something like this would allow setting just the things to override:

countdown.setFormat({
    singular: ' millisecond| second| minute| hour| day| week| month| year| decade| century| millennium'
    plural: ' milliseconds| seconds| minutes| hours| days| weeks| months| years| decades| centuries| millennia',
    last: ' and ',
    delim: ', ',
    empty: ' ',
    formatter: function(n){ return n.String(); }
});

It's nice and compact to allow those label lists to be simple pipe ('|') delimited strings, but it should also accept an array of strings.

countdown.setFormat({
    singular: [' millisecond', ' second', ' minute', ' hour', ' day',
        ' week', ' month', ' year', ' decade', ' century', ' millennium']
    plural: [' milliseconds', ' seconds', ' minutes', ' hours', ' days',
        ' weeks', ' months', ' years', ' decades', ' centuries', ' millennia']
});

TypeError: countdown__WEBPACK_IMPORTED_MODULE_1___default(...) is not a function

When I attempt to import countdown

import countdown from 'countdown';

I get the following error

Uncaught TypeError: countdown__WEBPACK_IMPORTED_MODULE_1___default(...) is not a function
    at TimerCountdown (main.42dec686241258517455.hot-update.js:58:80)
    at renderWithHooks (react-dom.development.js:14985:1)
    at mountIndeterminateComponent (react-dom.development.js:17811:1)
    at beginWork (react-dom.development.js:19049:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
    at invokeGuardedCallback (react-dom.development.js:4056:1)
    at beginWork$1 (react-dom.development.js:23964:1)
    at performUnitOfWork (react-dom.development.js:22776:1)
    at workLoopSync (react-dom.development.js:22707:1)

And when I console log countdown I get an object instead of a function.
console.log(countdown) => returs {}
hence the countdown is not a function error...

How to Set a Countdown in Node.js with time zone?

How to Set a Countdown in Node.js with time zone?

I need:
begin at noon Eastern Standard Time on Wednesday November 22, 2017

today is 2017.11.01
and I used this code for checking tommorrow

const countdown = require('countdown');
var aaa = countdown( new Date(2017, 11, 2) ).toString();
console.log(aaa)

But my Output is:
1 month, 19 hours, 21 minutes and 11 seconds
That Output is incorrect maybe because I'm in uae Now

Multiple timers on one page in a loop

Is it possible to have multiple timers on one page in a loop? I am having this strange issue and apologies if I misunderstand JS loops

Below works fine

    var time = [];
    time[0] = new Date();
    time[0].setSeconds(time[0].getSeconds() + 10);

    time[1] = new Date();
    time[1].setSeconds(time[1].getSeconds() + 20);

    timerId = [];
    timerId[0] =
        countdown(
                time[0],
                function (ts) {
                    $('#buildingsTime0').text(pad(ts.days) + ":" + pad(ts.minutes) + ":" + pad(ts.seconds));
                    if(ts.value > 0) {
                        window.clearInterval(timerId[0]);
                    }     
                }
            );

    timerId[1] =
        countdown(
                time[1],
                function (ts) {
                    $('#buildingsTime1').text(pad(ts.days) + ":" + pad(ts.minutes) + ":" + pad(ts.seconds));
                    if(ts.value > 0) {
                        window.clearInterval(timerId[1]);
                    }     
                }
            );

But it does not work in a loop. See comments in the code

    var time = [];
    time[0] = new Date();
    time[0].setSeconds(time[0].getSeconds() + 10);

    time[1] = new Date();
    time[1].setSeconds(time[1].getSeconds() + 20);

    timerId = [];
    
    for(var i = 0; i < time.length; i++) {
        console.log(i);
        //var x = i;
        // issue 1 two countdowns initiated but after first run there is only one left 
        timerId[i] =
            countdown(
                    time[i],
                    function (ts) {
                        console.log('#buildingsTime' + x);
                        // issue 2, somehow #buildingsTime is attached to #buildingsTime2 even though i is either 0 or 1 but never 2
                        $('#buildingsTime' + i).text(pad(ts.days) + ":" + pad(ts.minutes) + ":" + pad(ts.seconds));
                        
                        // also tried var x = i; above which seems to fix issue 2, but not issue 1, there is only one timer still
                        //$('#buildingsTime' + x).text(pad(ts.days) + ":" + pad(ts.minutes) + ":" + pad(ts.seconds));
                        if(ts.value > 0) {
                            window.clearInterval(timerId[0]);
                        }     
                    }
                );
    }

Thanks!

Sorry for spamming your inbox, but I wanted to say thanks for this great project.

I have just found out that starting with 2.4 you display timespans between two UTC dates in the users' local time. As someone who is using 2.3.x in production this feature is godsent, and I am very happy to have the upgrades available.

Thanks again for putting your effort into this project.

Countdown will countup instead after reaching 0 seconds

After the countdown finishes, it counts up instead of showing my desired text... have I done something wrong?

countdown.setLabels( ' millisecond|s|m|hr|d|w| M| Y| decade| century| millennium', ' millisecond|s|m|hr|d|w| M| Y| decade| century| millennium', '', '', 'My desired end text');

$scope.countdownTimer = countdown( dateObj,null, countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS).toString();

Problem with countdown

Hi
I want to start the timer by pressing the button. I wrote this function

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <script type="text/javascript" src="countdownjs/countdown.min.js"></script>
    <title>countdownjs</title>
</head>

<body>

<table width="90%" cellspacing="1" cellpadding="6" align="center" border="1">
<tr>
    <td>
        <div id="counter"></div>
    </td>
</tr>
<tr>
    <td>
        <input type="text" id="timespent" value="1437670253">
        <input type="button" value="Start" onclick="start_countdown();">

        <script type="text/javascript">
        <!--
            function start_countdown() {
                var time = document.getElementById('timespent').value;
                countdown(
                    new Date(time * 1000),
                    function(ts) {
                        document.getElementById('counter').innerHTML = ts.toHTML();
                    }, countdown.DEFAULTS
                );
            }
        // -->
        </script>
    </td>
</tr>
</table>

</body>

</html>

When you first run it works fine, but if you change the time and again press the "Start" then the timer begins to fail. What I did wrong?

Unnecessary comma in generated text

Thanks for package!

Found one tiny but annoying bug:
code countdown(null, Date.now() + 135 * 1000) returns 2 minutes, and 15 seconds.

Comma here is unnecessary.

Modify localization interface

Hello!
I want translate interface into Russian language, but could not make that correctly because current functional allow use only one 'plural', but for Russian need two.
Example for seconds

1       - секунда
2 - 4   - секунды
5 - 20  - секунд
21      - секунда
22 - 24 - секунды
25 - 30 - секунд

Russian localization must be so

countdown.setLabels(
    ' миллисекунда| секунда| минута| час| день| неделя| месяц| год| декада| столетие| тысячелетие',
    ' миллисекунды| секунды| минуты| часа| дня| недели| месяца| года| декады| столетия| тысячелетия',
    ' миллисекунд| секунд| минут| часов| дней| недель| месяцев| лет| декад| столетий| тысячелетий',
    ' и ',
    ', ',
    '');

Please, modify setLabels function for these.
Thanks

Countdownjs

Would like to have countdown started by button instead of auto

version mismatch in v2.5.2

Hi,
just letting you know that you have the wrong version declared (v2.5.0) in the package.json & bower for the release v2.5.2.

Cheers!

is:issue is:open How to use the end date/time callback

The api spec from the doc is: var timespan = countdown(start|callback, end|callback, units, max, digits);

If I specify the end callback function, there is javascript error or can't be compiled. How to use the "end event callback" indeed??

I would like to stop the countdown once it reaches the date or time.
Many thanks,

Not working in Firefox?

Greetings and thanks for your software.
I've tried the snippet from the docs:

var timerId =
  countdown(
    new Date('2021-11-24 13:00:00 GMT+0100'),
    function(ts) {
      document.getElementById('pageTimer').innerHTML = ts.toHTML("strong");
    },
    countdown.HOURS|countdown.MINUTES);

it works in Chrome 94 but not in Firefox 94. Am I doing something wrong?
Thanks in advance
Regards

Document the possibility to specify duration directly

It's a really handy feature we discussed on the BitBucket issue tracker. It doesn't look like it's documented anywhere. The BitBucket repo is gone, but I'll dump what I have from the notification e-mails (I can forward them to you formatted properly if you give me your email address):

Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?View this issue or add a comment by replying to this email.Unwatch this issue to stop receiving email updates. Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?View this issue or add a comment by replying to this email. Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts? Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts? Stephen McKamey commented on issue #16: Add an API for specifying duration directly This is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 24*30hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?     View this issue or add a comment by replying to this email. Unwatch this issue to stop receiving email updates. Unwatch this issue to stop receiving email updates.    


Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?View this issue or add a comment by replying to this email. Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts? Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts? Stephen McKamey commented on issue #16: Add an API for specifying duration directly This is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?     View this issue or add a comment by replying to this email.
Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts? Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts? Stephen McKamey commented on issue #16: Add an API for specifying duration directly This is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?    
Stephen McKamey commented on issue #16:Add an API for specifying duration directlyThis is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 24
30hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts? Stephen McKamey commented on issue #16: Add an API for specifying duration directly This is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 2430hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?    
Stephen McKamey commented on issue #16:
Add an API for specifying duration directly
This is definitely possible and consistent with the purpose of countdown.js. One complication is that countdownjs's "secret sauce" is in that it has an anchoring start or end date. This helps interpret the duration of time when it is ambiguous. For example, 28 days might be "1 month" when the anchoring date is in February, but if it were in December then it would be "4 weeks". 30 days in February would display "1 month and 2 days" unless it was a leap year and then it would return "1 month and 1 day". In November 30 days would be "1 month" but in December it would be "4 weeks and 2 days".In other words, context is important when representing durations of time. This usually comes down to the fact that human months are a pretty broken concept.Taking your example, you have implicitly anchored it to "now". In the case of hours or minutes, it will probably always return the same value. But if you added 24
30hours, you might see the result change as the anchoring date changed.But your feature request is still valid. Here's my API proposal: allow countdown(...) to take mock timespan objects as either the start or end arguments. I'm still noodling on what that would look like but here is a possibility:countdown( null, // now { "hours": 48 }, countdown.ALL).toString(); This would format the duration of "48 hours from now". I think the interpretation would need to be that it takes the other date (substituting new Date() for null) and modifies it by the given timespan. On subsequent iterations (e.g., if the other "date" is the callback function) it doesn't change the end date but would continue to count down to it. So this would be similar to what you were showing without having to create a Date and run the helper function. The important thing to remember is that the resulting end (or start) date would be generated from the mock timespan once not on every iteration. I think this is important otherwise it would remain a fixed time interval which would be less useful.Thoughts?

Display units based on config, not value

When a value is 0, the formatList function does not add it to the list, even though it is configured to be displayed in the timpstamp units property. This means that the countdown looks something like this:

2 hours
19 minutes
1 second

and a second later looks like this:

2 hours
19 minutes

and then 19 minutes later:

2 hours
1 second

While, IMHO it should be:

2 hours
19 minutes
0 seconds

and

2 hours
0 minutes
1 second

respectively

Library isn't bundled by react native packager

I'm sure this is something I'm doing wrong, but I can't figure it out and I'm hoping someone here might have some experience with this.

For some reason, when I require this library and bundle my source code with the react native packager, the source of this library doesn't get bundled and therefore I get exceptions when calling the functions. I'm using typescript and have tried all the known ways of importing, and also have tried changing the .js source that is compiled.

What I have:

  1. Module is included in package.json and appears in my node_modules
  2. I'm using typescript, and the compiled js file has the require('countdown') line.
  3. If I inspect the output bundle, or log the var countdown = require('countdown'), I can see that the source for countdown.js isn't included in the bundle.
  4. If I use webpack to create a web bundle, it works as expected.

Here's the compiled js code which is having issues:

"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var RX = require("reactxp");
var countdown = require("countdown");
var styles = {
    outerContainer: RX.Styles.createViewStyle({
        flexDirection: "row"
    }),
    innerContainer: RX.Styles.createViewStyle({
        flexDirection: "column",
        alignItems: "center",
        paddingHorizontal: 5
    })
};
var CountdownTimer = (function (_super) {
    __extends(CountdownTimer, _super);
    function CountdownTimer() {
        var _this = _super.call(this) || this;
        _this._setStateToNow = function () {
            _this.setState({ currentDate: new Date(Date.now()) });
        };
        _this.state = { currentDate: new Date() };
        return _this;
    }
    CountdownTimer.prototype.componentDidMount = function () {
        this.timerId = setInterval(this._setStateToNow, 1000);
    };
    CountdownTimer.prototype.componentWillUnmount = function () {
        clearInterval(this.timerId);
    };
    CountdownTimer.prototype.render = function () {
        // THIS LINE FAILS SINCE 'countdown' is {}
        var diff = countdown(this.state.currentDate, this.props.untilDate, CountdownTimer.DIFF_ARGS);

        ....

    };
    CountdownTimer.DIFF_ARGS = countdown.DAYS |
        countdown.HOURS |
        countdown.MINUTES |
        countdown.SECONDS;
    return CountdownTimer;
}(RX.Component));
exports.CountdownTimer = CountdownTimer;

I have this library setup and imported the exact same way as others (e.g. lodash, reactxp), and this is the only one that doesn't get bundled.

I'm running the packager the standard way, and have tried clearing node_modules and all the caches.

Here's an SO question I also opened to try get some help:

I have even tried adding a require call to my root index.js, which also doesn't work

Feature: trigger function when end date reached

I see the start and end params accept a callback function, but would it be possible to add another callback function for when the end date is reached.

So it can trigger some code when the end date is met. Maybe this already has that functionality? I just could not get it to do what I wanted.

React Native Bug

Hi guys,

I have been using this module for a while with React Native and it works very well.

However, I had to make a simple change on the way that the module is exported.

Take a look here: master...matheusmatos:master

I'm not sure if I can send a pull request to that without cause incompatibility on the browser.

Basically, the module is an object instead of a function when imported with:

import countdown from 'countdown'

What do you think? Can I send a PR?

Thank you for this awesome library =)

Zero pad milliseconds with 3 digits?

Sorry for not spending more time.

I would like to zero pad weeks, days, hours, minutes with two digits and then zero pad milliseconds with 3 digits.

So you would get below output from the countdown().toString

01 day, 09 hours, 05 minutes, 03 seconds and 005 milliseconds
08 days, 02 hours, 09 minutes, 16 seconds and 095 milliseconds

Perhaps the setLabels format function could provide number and unit of said number to then zero pad differently

Update npm package

Please consider updating your npm package with your latest commit , not working on angular 12 (last updated 6 years ago), I
replaced the js file on node modules with your latest commit, and worked again.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.