cached-date
TypeScript icon, indicating that this package has built-in type declarations

1.0.3 • Public • Published

cached-date

Caches standard Date formats to boost performance

Overview

The built-in Date class has several methods that produce standard date strings. These strings are not cached (at least in node.js), so each call to the same method on the same Date incurs the expense of generating the string. cached-date provides cached versions of these methods that run between 116 and 331 times faster in repeat calls (on node.js), depending on the method.

Usage

The methods illustrated here all yield the strings equivalent to their namesake methods lacking the word 'Cached'.

require('cached-date');
let date = new Date();
 
let str = date.toCachedString();
let dateStr = date.toCachedDateString();
let iso = date.toCachedISOString();
let json = date.toCachedJSON();
let time = date.toCachedTimeString();
let utc = date.toCachedUTCString();
 
let datetimeStr = date.toCachedDateTimeString(); // in MySQL DATETIME format

The extra method toCachedDateTimeString() does not correspond to an uncached Date method. It retrieves the GMT date/time in the format that the MySQL DATETIME type requires.

The module monkey patches the Date class instead of subclassing it, so that caching is available no matter how the Date is acquired. When you don't know whether the patch is available, you can flexibly handle dates as follows:

function gimmeAnyKindOfDate(date) {
    let isoStr = date.toCachedISOString ? date.toCachedISOString() : date.toISOString();
    // use isoStr
}

Performance geeks may care to know that the following code executes a tad faster:

function gimmeAnyKindOfDate(date) {
    let isoStr = date.toCachedISOString !== undefined
            ? date.toCachedISOString() : date.toISOString();
    // use isoStr
}

Typings are included for Typescript, but in order to get them, you'll need to import the package (not require() it):

import 'cached-date';
let date = new Date();

Applications

This monkey patch can marginally improve the performance of servers that repeatedly acquire strings for the same Date instances or for insigificantly different Date instances.

Not many applications may benefit from Date caching, but here are some examples:

  • Tables in a database record the time at which a web server client requested creation or modification of a row. Multiple rows across multiple tables will have identical times when produced or modified as a result of the same client request.
  • In some databases, such as Postres, configuring for automatically updating rows with their latest modification times is laborious and challenging to manage. Developers on a budget may opt to push the modification time with each update. Devs can keep their interfaces generic by passing around date objects and then under-the-hood (perhaps via library hooks) use cached date strings.
  • Client software may hand Dates that it itself needs to libraries, and if both the library and the client generate the same Date strings, they do the work redundantly. If the dev owns the library or the library provides appropriate hooks, caching can eliminate that redundancy.

Of course, other factors such as choice of algorithm or blocking resources often significantly outweigh the costs of regenerating Dates. Even so, on platforms such as Node.js that has a single thread dispatching all requests without blocking, the fewer clock cycles per request, the more requests serviced per unit time, up until server saturation, which we strive to ensure never happens.

And of course, if you can pass around the generated date string instead of a Date instance, that would be even faster. This package is for those who don't have that option or who prefer to pass a Date around for other reasons (such as for encapsulating the choice of string format).

Performance

The included performance benchmarks shows varying but dramatic speed improvements on second and subsequent method calls. The module could help win a few clock cycles in the high performance environments in which node typically runs.

Here are the results of running node benchmark.js on my machine*:

toString() x 190,687 ops/sec ±0.97% (90 runs sampled)
toCachedString() x 48,399,303 ops/sec ±0.81% (85 runs sampled)
  ^ cached:non-cached = 254:1
toDateString() x 417,305 ops/sec ±0.76% (90 runs sampled)
toCachedDateString() x 48,489,030 ops/sec ±0.83% (86 runs sampled)
  ^ cached:non-cached = 116:1
toISOString() x 278,232 ops/sec ±0.78% (88 runs sampled)
toCachedISOString() x 48,592,052 ops/sec ±0.74% (86 runs sampled)
  ^ cached:non-cached = 175:1
toJSON() x 146,637 ops/sec ±0.97% (85 runs sampled)
toCachedJSON() x 48,531,761 ops/sec ±0.84% (88 runs sampled)
  ^ cached:non-cached = 331:1
toTimeString() x 263,246 ops/sec ±0.72% (88 runs sampled)
toCachedTimeString() x 48,191,770 ops/sec ±0.89% (89 runs sampled)
  ^ cached:non-cached = 183:1
toUTCString() x 289,091 ops/sec ±0.73% (90 runs sampled)
toCachedUTCString() x 48,569,979 ops/sec ±0.85% (88 runs sampled)
  ^ cached:non-cached = 168:1
MySQL DATETIME** x 214,655 ops/sec ±0.86% (90 runs sampled)
toCachedDateTimeString() x 48,231,859 ops/sec ±1.06% (86 runs sampled)
  ^ cached:non-cached = 225:1

* Run on a 2.5G Hz Intel Core i7 MacBook Pro

** Implemented as date.toISOString().slice(0, 19).replace('T', ' ')

License

MIT License

Copyright (c) 2017 Joseph T. Lapp

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Readme

Keywords

Package Sidebar

Install

npm i cached-date

Weekly Downloads

1

Version

1.0.3

License

MIT

Last publish

Collaborators

  • jtlapp