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();
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();
}
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();
}
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.