npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

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

About

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

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

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

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

Open Software & Tools

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

© 2024 – Pkg Stats / Ryan Hefner

vintage-time

v1.5.2

Published

DateTime x DateOnly library with locale support. Compatible with sequelize, joi, momentjs and plain javascript Dates

Downloads

20

Readme

vintage-time

npm version codecov node test and build workflow contributions welcome

DateTime x DateOnly library with locale support. Compatible with sequelize, joi and plain javascript Dates

Distributed through the npm packge vintage-time

Installation

npm install vintage-time

or

yarn add vintage-time

Usage

This library defines a clear separation between values that should be DateOnly and those that should be DateTime.

For this end, we have two distinc classes that are (kinda) compatible to each other:

  • DateOnly - only stores the date part (year, month and day). It completly ignores the timezone.
  • DateTime - stores date and time (year, month, day, hour, minute, second, millisecond, timezone).

Examples:

const date = new Date('2024-01-01 12:44:00.567');

const dateOnly = DateOnly.fromJsDate(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"

const dateTime = DateTime.fromJsDate(date);
console.log(dateTime.toString()); // logs: "2024-01-01T12:44:00.567" + localTimezoneOffset

Simplified usage

The library ships a set of helper functions that automatically handle most scenarios and return the appropriate result.

toDateOnly

This method converts a date compatible value into a DateOnly instance. So it works out of the box with values like: numbers, Date, string, Moment, DateTime and DateOnly.

An alternative to this method is to call DateOnly.fromAnyDate directly which handles almost the same scenarios. Another one would be to call any of the specialized factory methods depending on the input.

let date, dateOnly;

// # Create from a plain objects:
date = {year: 2024, month: 1, day: 1};
dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"

// # Create from a Date object:
date = new Date('2024-01-01 12:44:00.567');
dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"

// # Create from a numeric timestamp:
date = new Date('2024-01-01 12:44:00.567');
dateOnly = toDateTime(date.getTime());
console.log(dateOnly.toString()); // logs: "2024-01-01"

// # Create from a Moment object:
date = moment('2024-01-01 12:44:00.567');
const dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"

// # Create from a formatted date-time string:
date = '2024-01-01 12:44:00.567'; // '2024-01-01T12:44:00.567' also works!
dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"

// # Create from a formatted date-only string:
date = '2024-01-10';
dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-10"

// # Create from a formatted date-time string: (Notice that the timezone is ignored when working with DateOnly)
date = '2024-01-01 12:44:00.567Z'; // '2024-01-01T12:44:00.567Z' also works!
dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"
date = '2024-01-01 12:44:00.567-10:00'; // '2024-01-01T12:44:00.567Z' also works!
dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"
date = '2024-01-01 12:44:00.567+10:00'; // '2024-01-01T12:44:00.567Z' also works!
dateOnly = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01"

Calling the method with null or undefined will always return undefined

toDateOnly.now

Shortcut for calling DateOnly.now() which returns a DateOnly instance from the current system timestamp.

const dateOnly = toDateTime.now(); // Simillar to: toDateTime(new Date())

toDateTime

This method converts a date compatible value into a DateOnly instance. So it works out of the box with values like: numbers, Date, string, Moment, DateTime and DateOnly.

An alternative to this method is to call DateOnly.fromAnyDate directly which handles almost the same scenarios. Another one would be to call any of the specialized factory methods depending on the input.

let date, dateTime;

// # Create from a plain objects specifying only the date part:
date = {year: 2024, month: 1, day: 1};
dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-01"

// # Create from a plain objects specifying the date and time part:
date = {year: 2024, month: 1, day: 1, hour: 22, second: 1, timezone: 'UTC'};
dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-01T22:00:01.000Z"

// # Create from a plain objects specifying the date and time part: (Ommiting timezone automatically picks the local system timezone)
date = {year: 2024, month: 1, day: 1, hour: 22, second: 1};
dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-01T22:00:01.000" + localTimezoneOffset

// # Create from a plain objects specifying the date and time part: (Timezone offset can be used instead of a timezone name)
date = {year: 2024, month: 1, day: 1, hour: 22, second: 1, offset: 7};
dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-01T22:00:01.000+07:00"

// # Create from a Date object:
date = new Date('2024-01-01 12:44:00.567');
dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-01T12:44:00.567" + localTimezoneOffset

// # Create from a numeric timestamp:
date = new Date('2024-01-01 12:44:00.567');
dateTime = toDateTime(date.getTime());
console.log(dateTime.toString()); // logs: "2024-01-01T12:44:00.567" + localTimezoneOffset

// # Create from a Moment object:
date = moment('2024-01-01 12:44:00.567');
const dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-01T12:44:00.567" + localTimezoneOffset

// # Create from a formatted date-time string:
date = '2024-01-01 12:44:00.567'; // '2024-01-01T12:44:00.567' also works!
dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-01T12:44:00.567" + localTimezoneOffset

// # Create from a formatted date-only string: (DateOnly instances are always treated as UTC dates)
date = '2024-01-10';
dateTime = toDateTime(date);
console.log(dateTime.toString()); // logs: "2024-01-10T00:00:00.000Z"

// # Create from a formatted date-time string: (The original timezone in the string is used)
date = '2024-01-01 12:44:00.567Z'; // '2024-01-01T12:44:00.567Z' also works!
dateTime = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01T12:44:00.567Z"
date = '2024-01-01 12:44:00.567-10:00'; // '2024-01-01T12:44:00.567Z' also works!
dateTime = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01T12:44:00.567-10:00"
date = '2024-01-01 12:44:00.567+10:00'; // '2024-01-01T12:44:00.567Z' also works!
dateTime = toDateTime(date);
console.log(dateOnly.toString()); // logs: "2024-01-01T12:44:00.567+10:00"

Calling the method with null or undefined will always return undefined

toDateTime.now

Shortcut for calling DateTime.now(locale) which returns a DateTime instance from the current system timestamp.

const dateTime = toDateTime.now(); // Simillar to: toDateTime(new Date())

toDateTime.tz

Shortcut for calling toDateTime(anyDate, locale).toTimezone(tz) which returns a DateTime instance at a specific timezone.

const dateTime = toDateTime.tz('2023-12-31', 'Asia/Jakarta'); // Change the TZ from UTC to +07:00
console.log(dateTime.toISOString(false)); // Output "2023-12-31T07:00:00.000+07:00"

toDateTime.as

It changes the timezone of the date-time but keeps the original date and time values:

  • year
  • month
  • day
  • hour
  • minutes
  • second
  • millisecond
let dateTime = toDateTime.tz('2023-12-31', 'Asia/Jakarta'); // Change the TZ from UTC to +07:00 (shift the offset to the new timezone)
console.log(dateTime.toISOString(false)); // Output "2023-12-31T07:00:00.000+07:00"
console.log(dateTime.toISOString(true)); // Output "2023-12-31T07:00:00.000+07:00"

DateTime.isEqual(dateTime, '2023-12-31'); // true

dateTime = toDateTime.as('2023-12-31', 'Asia/Jakarta'); // Change the TZ from UTC to +07:00 keeping the original date and time values
console.log(dateTime.toISOString(false)); // Output "2023-12-31T00:00:00.000+07:00"
console.log(dateTime.toISOString(true)); // Output "2023-12-30T17:00:00.000Z"

DateTime.isEqual(dateTime, '2023-12-31'); // false

Comparing dates

The best approach is to use the built-in methods which check equality properly and convert all values to the proper date class.

  • isEqual - checks equality between dates (=== using valueOf())
  • isBefore - checks dateA < dateB
  • isAfter - checks dateA > dateB
  • isEqualBefore - checks dateA <= dateB
  • isEqualAfter - checks dateA >= dateB
const dateTimeA = toDateTime('2024-01-01T12:44:00.567Z');
const dateTimeB = toDateTime('2024-01-02T07:33:51.120-03:00');
const dateOnlyA = toDateOnly(toDateTime);
const dateOnlyB = toDateOnly(toDateTime);

// Use DateTime for comparing dates for both their date and time values
console.log(DateTime.isEqual(dateOnlyA, dateOnlyA)); // true
console.log(DateTime.isEqual(dateTimeA, dateTimeA)); // true
console.log(DateTime.isEqual(dateOnlyA, dateTimeA)); // false
console.log(DateTime.isEqual(dateTimeA, dateOnlyA)); // false
console.log(DateTime.isEqual(dateOnlyA, dateOnlyB)); // false
console.log(DateTime.isEqualOrBefore(dateOnlyA, dateOnlyB)); // true
console.log(DateTime.isBefore(dateOnlyA, dateOnlyB)); // true
console.log(DateTime.isEqualOrAfter(dateOnlyA, dateOnlyB)); // false
console.log(DateTime.isAfter(dateOnlyA, dateOnlyB)); // false

// Use DateOnly when time does not matter and you only want to check the date parts
console.log(DateOnly.isEqual(dateOnlyA, dateOnlyA)); // true
console.log(DateOnly.isEqual(dateTimeA, dateTimeA)); // true
console.log(DateOnly.isEqual(dateOnlyA, dateTimeA)); // true
console.log(DateOnly.isEqual(dateTimeA, dateOnlyA)); // true
console.log(DateOnly.isEqual(dateOnlyA, dateOnlyB)); // false
console.log(DateOnly.isEqualOrBefore(dateOnlyA, dateOnlyB)); // true
console.log(DateOnly.isBefore(dateOnlyA, dateOnlyB)); // true
console.log(DateOnly.isEqualOrAfter(dateOnlyA, dateOnlyB)); // false
console.log(DateOnly.isAfter(dateOnlyA, dateOnlyB)); // false

Still, it also works through the method valueOf. It implicitly works as long as both sides of the operator are values of the same type. In the other situations an explicitly call is necessary.

const dateTimeA = toDateTime('2024-01-01T12:44:00.567Z');
const dateTimeB = toDateTime('2024-01-02T07:33:51.120-03:00');

console.log(dateTimeA < dateTimeB); // true
console.log(dateTimeA <= dateTimeB); // true
console.log(dateTimeA > dateTimeB); // false
console.log(dateTimeA >= dateTimeB); // false

// Equality - Note that we explicitly use `.valueOf()` here to avoid comparing by reference
console.log(dateTimeA.valueOf() === toDateOnly(dateTimeA).valueOf()); // true
console.log(dateTimeA.valueOf() !== dateTimeB.valueOf()); // true
console.log(dateTimeA.valueOf() !== dateTimeA.valueOf()); // false

const dateOnlyA = toDateOnly(toDateTime);
const dateOnlyB = toDateOnly(toDateTime);

console.log(dateOnlyA < dateOnlyB); // true
console.log(dateOnlyA <= dateOnlyB); // true
console.log(dateOnlyA > dateOnlyB); // false
console.log(dateOnlyA >= dateOnlyB); // false

// Equality - Note that we explicitly use `.valueOf()` here to avoid comparing by reference
console.log(dateOnlyA.valueOf() === toDateOnly(dateTimeA).valueOf()); // true
console.log(dateOnlyA.valueOf() !== dateOnlyB.valueOf()); // true
console.log(dateOnlyA.valueOf() !== dateOnlyA.valueOf()); // false
// 

Plugins

Sequelize

vintage-time requires sequelize 6.x installed. Please make sure to have it installed in order to work.

Even without using the plugin, sequelize already accepts both DateOnly and DateTime for queries.

Since sequeize only supports JS natve Dates, we need to define getters and setters to our Date properties in order to use a different class. This plugin offers two built-in methods to define the getters and setters.

dateOnlyColumn

function dateOnlyColumn(propertyName: string, strict?: boolean): {
    type: typeof DataTypes.DATEONLY,
    get(): DateOnly | null;
    set(value: any): void;
};

Used to defined a DateOnly column (sequelize type DATEONLY).

const {dateOnlyColumn} = require('vintage-time/plugins/sequelize');
const model = sequelize.define('DateDummy', {
        startDate: {
            ...dateOnlyColumn('startDate'),
            allowNull: true,
        },
    },
    {tableName: 'dummies'}
);

// ...

const entry = model.findOne();
console.log(entry.startDate instanceof DateOnly); // true

The parameter strict when true enforces that the setter should only accept DateOnly instances. Otherwise when false it attempts to convert any value to a DateOnly instance.

dateTimeColumn

function dateTimeColumn(propertyName: string, strict?: boolean): {
    type: typeof DataTypes.DATEO,
    get(): DateTime | null;
    set(value: any): void;
};

Used to defined a DateTime column (sequelize type DATE).

const {dateTimeColumn} = require('vintage-time/plugins/sequelize');
const model = sequelize.define('DateDummy', {
        archivedAt: {
            ...dateTimeColumn('archivedAt'),
            allowNull: false,
            defaultValue: () => toDateTime.now(),
        },
    },
    {tableName: 'dummies'}
);

// ...

const entry = model.findOne();
console.log(entry.archivedAt instanceof DateTime); // true

The parameter strict when true enforces that the setter should only accept DateOnly instances. Otherwise when false it attempts to convert any value to a DateTime instance.

Joi

vintage-time requires joi 17.x installed. Please make sure to have it installed in order to work.

The plugin exposes a set of validators to be used together with Joi validation schemas.

anyDate

Accepts both DateOnly and DateTime compatible strings. Unless it is set to raw(), the validator outputs a DateTime instance.

const {anyDate} = require('vintage-time/plugins/joi');
joi = joi.extend(anyDate);

const schema = joi.object().keys({date: joi.anyDate()});
// These are valid strings
schema.validate({date: '2020-07-19'});
schema.validate({date: '2020-07-19 00:00:00.000Z'});
schema.validate({date: '2020-07-19 00:00:00Z'});
schema.validate({date: '2020-07-19 00:00:00-03:00'});
schema.validate({date: '2020-07-19 01:20:03'});
schema.validate({date: '2020-07-19 01:20:03.657Z'});
schema.validate({date: '2020-07-19T00:00:00Z'});
schema.validate({date: '2020-07-19T00:00:00-03:00'});
schema.validate({date: '2020-07-19T01:20:03'});
schema.validate({date: '2020-07-19T01:20:03.657Z'});

// These are not
schema.validate({date: '07/19/2020'});
schema.validate({date: '2020/07/19'});
schema.validate({date: '01:20:03.657Z'});
schema.validate({date: '2020/07/19 at 3:00 PM'});

dateOnly

Accepts DateOnly compatible strings. Unless it is set to raw(), the validator outputs a DateOnly instance.

const {dateOnly} = require('vintage-time/plugins/joi');
joi = joi.extend(dateOnly);

const schema = joi.object().keys({date: joi.dateOnly()});
// These are valid strings
schema.validate({date: '2020-07-19'});
schema.validate({date: '1990-01-11'});

// These are not
schema.validate({date: '2020-07-19 00:00:00Z'});
schema.validate({date: '2020-07-19 00:00:00-03:00'});
schema.validate({date: '2020-07-19 01:20:03'});
schema.validate({date: '2020-07-19 01:20:03.657Z'});
schema.validate({date: '2020-07-19T01:20:03'});
schema.validate({date: '2020-07-19T01:20:03.657Z'});
schema.validate({date: '2020-07-19T00:00:00Z'});
schema.validate({date: '2020-07-19T00:00:00-03:00'});
schema.validate({date: '07/19/2020'});
schema.validate({date: '2020/07/19'});
schema.validate({date: '01:20:03.657Z'});
schema.validate({date: '2020/07/19 at 3:00 PM'});

dateTime

Accepts DateTime compatible strings. Unless it is set to raw(), the validator outputs a DateTime instance.

const {dateTime} = require('vintage-time/plugins/joi');
joi = joi.extend(dateTime);

const schema = joi.object().keys({date: joi.dateTime()});
// These are valid strings
schema.validate({date: '2020-07-19 00:00:00.000Z'});
schema.validate({date: '2020-07-19 00:00:00Z'});
schema.validate({date: '2020-07-19 00:00:00-03:00'});
schema.validate({date: '2020-07-19 01:20:03'});
schema.validate({date: '2020-07-19 01:20:03.657Z'});
schema.validate({date: '2020-07-19T00:00:00Z'});
schema.validate({date: '2020-07-19T00:00:00-03:00'});
schema.validate({date: '2020-07-19T01:20:03'});
schema.validate({date: '2020-07-19T01:20:03.657Z'});

// These are not
schema.validate({date: '2020-07-19'});
schema.validate({date: '1990-01-11'});
schema.validate({date: '07/19/2020'});
schema.validate({date: '2020/07/19'});
schema.validate({date: '01:20:03.657Z'});
schema.validate({date: '2020/07/19 at 3:00 PM'});