# How to work with Date | JavaScript Weird Parts

Working with JavaScript has never been easy. You always required continuous learning and exploration of new APIs/specs. One of the toughest things is working with _Date_. You always struggle to find a suitable method or end up importing external libraries like [momentjs](https://momentjs.com/). Here in this article, I will explain how you can create a simple utility library for all your needs by using plain JavaScript.

**Table of Contents:**

- [1. Create a simple exportable module](#1-create-a-simple-exportable-module)
- [2. Creating a Date](#2-creating-a-date)
  - [Simple hacks to Date constructor](#simple-hacks-to-date-constructor)
- [3. Get day, month, year](#3-get-day-month-year)
  - [Simple hacks to Date getters](#simple-hacks-to-date-getters)
- [4. Set day, month, year](#4-set-day-month-year)
  - [Simple hacks working with month(add/subtract)](#simple-hacks-working-with-monthaddsubtract)
- [5. Format a date](#5-format-a-date)
  - [Simple custom format method](#simple-custom-format-method)
- [6. Invalid Date](#6-invalid-date)
- [Conclusion](#conclusion)
- [Some useful hacks](#some-useful-hacks)
- [References](#references)

## 1. Create a simple exportable module

Before going further, Let's create an exportable module. Exporting methods can vary according to the framework used. Below, I have mention a few examples of how to export a method as a module.

**Nodejs:**

```js
//date.js
exports.isValid = (date) => {
  // TODO:
};
```

**React with Webpack:**

```js
//date.js
export const isValid = (date) => {
  // TODO:
};
```

**TypeScript:**

```ts
//date.ts
export const isValid = (date: Date) => {
  // TODO:
};
```

## 2. Creating a Date

**Date** class provide multiple ways to create an object. To get the current date object you can use `new Date()`, **Date** constructor without any parameter. The other way to create a Date object, use the number value in the constructor(new Date(num)). Here, **num** representing the number of milliseconds since January 1, 1970, 00:00:00.

**To get current Date:**

```js
/**
 * today: Get the current date
 */
exports.today = () => new Date();

// main.js
const { today } = require("./date");
console.log(today()); // 2021-08-22T15:59:47.482Z
```

**To get current timestamp in milliseconds:**

```js
// date.js

/**
 * now: Get the current timestamp
 */
exports.now = () => Date.now();

// main.js

const { today, now } = require("./date");
console.log(now()); // 1629647987489
```

### Simple hacks to Date constructor

```js
// date.js

const [HR, DAY, WEEK] = [
  60 * 60 * 1000,
  60 * 60 * 1000 * 24,
  60 * 60 * 1000 * 24 * 7,
];
exports.hourBefore = () => new Date(this.now() - HR);
exports.dayBefore = () => new Date(this.now() - DAY);
exports.weekBefore = () => new Date(this.now() - WEEK);

//main.js

console.log(hourBefore()); //2021-08-22T14:59:47.489Z
console.log(dayBefore()); // 2021-08-21T15:59:47.489Z
console.log(weekBefore()); // 2021-08-15T15:59:47.489Z
```

**Note:** Since a month can be 28,29,30 or 31 days base on the type of year. And same time timezone varies with a local date. So working with a date in the month is a little tricky. I have explained few hacks to work with months in the below setters examples.

## 3. Get day, month, year

Getting a day, month or year from a Date object is quite simple. There are a lot of getter methods within a date object.

**Sample:**

```js
const currentDate = today();
console.log(currentDate.toISOString()); // 2021-08-22T16:38:27.164Z
console.log(currentDate.getTime()); // 1629650307164
console.log(currentDate.getDate()); // 23
console.log(currentDate.getDay()); // 1
console.log(currentDate.getMonth()); // 7
console.log(currentDate.getFullYear()); // 2021
console.log(currentDate.getHours()); // 0
console.log(currentDate.getMinutes()); // 38
```

**Note:** Few of the biggest confusions are **getDay** and **getMonth**. These both two starts with **0**. Meaning, month _Jan_ and day _Sunday_ represent as _0_ in month and day respectively. This is very confusing for the first time. To work with month and day, You can create an enum/constant map.

```js
//date.js

const MONTHS = { 0: "January", 1: "February", 2: "March", 7: "August" }; // TODO: complete
exports.monthInString = (date) => {
  return MONTHS[date.getMonth()];
};

const DAYS = { 0: "Sunday", 1: "Monday", 2: "Tuesday", 3: "Wednesday" }; // TODO: complete
exports.dayOfWeek = (date) => {
  return DAYS[date.getDay()];
};

// main.js

console.log(monthInString(today())); // August

console.log(dayOfWeek(today())); // Monday
```

### Simple hacks to Date getters

With the new `Date.toLocaleString` method, Now it is very easy to get day/month as string. You can pass locale as _"en-US"_ and other options to format date string.

```js
// Get Day of the Week
console.log(today(), today().toLocaleString("en-US", { weekday: "long" })); // 021-08-22T16:58:30.238Z Monday
// Get month of the Year
console.log(today(), today().toLocaleString("en-US", { month: "long" })); // 021-08-22T16:58:30.238Z August
```

You can also collect all information at once using destructure array.

```js
const [month, day, year, hr, min, sec, meridiem] = new Date(
  2021,
  08,
  22,
  18,
  08,
  08
)
  .toLocaleString("en-US")
  .split(/\W+/); //// 9/22/2021, 8:08:08 PM
console.log(month, day, year, hr, min, sec, meridiem); // 9 22 2021 6 08 08 PM
```

If you want to format or prefix a day/month/hr/min with zero, You can do so by passing the option "2-digit". You can also show the full name of a month.

```js
const [month, day, year, hr, min, sec] = new Date(2021, 08, 22, 18, 08, 08)
  .toLocaleString("en-US", {
    day: "2-digit",
    month: "long",
    year: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false,
  })
  .split(/\W+/); //// 9/22/2021, 8:08:08 PM
console.log(month, day, year, hr, min, sec); // September 22 21 18 08 08
```

_For more options, You can read [this](https://www.w3schools.com/jsref/jsref_tolocalestring.asp) nice article._

## 4. Set day, month, year

Setting a day, month or year from a Date object is quite simple. Same as a getter, are a lot of setter methods available in a date object.

**List of setters:** <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date>

### Simple hacks working with month(add/subtract)

```js
// date.js
/**
 * addMonths: add a month to date
 * You can pass -(month) to subtract
 *
 * @param {Date} date
 * @param {number} months
 */
exports.addMonths = (date, months) => {
  var d = date.getDate();
  date.setMonth(date.getMonth() + +months);
  if (date.getDate() != d) {
    date.setDate(0);
  }
  return date;
};

exports.subMonths = (date, months) => this.addMonths(date, -1 * months);

//main.js

console.log(today(), addMonths(today(), 2)); //2021-08-22T16:30:11.826Z 2021-10-22T16:30:11.826Z
console.log(today(), subMonths(today(), 2)); //2021-08-22T16:34:10.895Z 2021-06-22T16:34:10.895Z
```

To learn more on adding/subtracting dates, Read below mention **StackOverflow** links.

- <https://stackoverflow.com/questions/2706125/javascript-function-to-add-x-months-to-a-date/36331522#36331522>
- <https://stackoverflow.com/questions/5645058/how-to-add-months-to-a-date-in-javascript/13633692#13633692>
- <https://stackoverflow.com/questions/2706125/javascript-function-to-add-x-months-to-a-date>

![1_1X-_xDbm03LntXVWYhKb7g.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1629660534629/5sSaai8WL.png)

## 5. Format a date

There are multiple default standard format methods supported by the Date objects. You can use method likes **toUTCString**, **toISOString**, **toLocaleString** to get formatted string of date. However, there is no standard custom format method supported by the Date object. [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#constructor) supports a lot of helper methods to work with date formatting.

**Note:** _Intl_ is not fully supported by all the browsers. You may have to polyfill methods based on need.

```js
var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));

// US English uses month-day-year order
console.log(new Intl.DateTimeFormat("en-US").format(date));
// → "12/19/2012"
// British English uses day-month-year order
console.log(new Intl.DateTimeFormat("en-GB").format(date));
// → "19/12/2012"

// Chinese
console.log(new Intl.DateTimeFormat("zh-TW").format(date));
// → "2012/12/20"
```

Same as _toLocaleString_, You can also pass options along with locale in _DateTimeFormat_ constructor.

```js
var options = {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric",
};
console.log(new Intl.DateTimeFormat("de-DE", options).format(date));
// → "Donnerstag, 20. Dezember 2012"
```

Learn more on _DateTimeFormat_: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat>

### Simple custom format method

Writing a format function is very complex. It evolves by parsing a date object, extract values and compact in a date string. As part of this article, we will not go in-depth. However based on the above useful utility methods, We can create a simple format function using replace command.

```js
//date.js
exports.formatString = (format, date) => {
  const [MM, DD, YYYY, hh, mm, ss, A] = date
    .toLocaleString("en-US", {
      day: "2-digit",
      month: "2-digit",
      year: "numeric",
      hour: "2-digit",
      minute: "2-digit",
      second: "2-digit",
    })
    .split(/\W+/);
  const timeMap = { MM, DD, YYYY, hh, mm, ss, A };
  return format.replace(/(\w+)/g, (key) => timeMap[key]);
};

// main.js
var date = new Date(2012, 11, 20, 3, 0, 0);
console.log(formatString("DD-MM-YYYY hh:mm:ss A", date)); // 20-12-2012 03:00:00 AM
```

**Note:** As mentioned above, This format method is not tested for production support. It is just to demonstrate how a simple format function can be written. You can think of more complex definitions to create a format function.

## 6. Invalid Date

**Invalid Date** is a spatial date object. Whenever you create a Date object with an invalid date value. Instead of throwing an error, It creates an object with a special value **Invalid Date**. This special object is very confusing. This will not throw any error in most of the operations performed on it. which can cause a lot of production issues. To avoid such issues, You can create an **isValid** function.

```js
//date.js
exports.isValid = (date) => date.toString() !== "Invalid Date";

//main.js
console.log(isValid(new Date("2021-08-22T16:30:11.826Z"))); // true
console.log(isValid(new Date("ff-08-22T16:30:11.826Z"))); // false
```

## Conclusion

In javascript, there is a lot of flexibility. However, This flexibility creates a lot of confusion and chaos. If you know these hacks, It can significantly improve your productivity. And a good way to learn, try and test in your project. Write more code and review more.

_If you are looking for more useful methods like these, Please checkout [30-seconds-of-typescript/](https://decipher.dev/30-seconds-of-typescript/)_

![helpful-tips-picture-id933100878.jpeg](https://cdn.hashnode.com/res/hashnode/image/upload/v1629660620442/ctP6b1OBd.jpeg)

## Some useful hacks

- Get timestamp without _now/getTime_ method

```js
console.log(+new Date());
//same as
console.log(new Date().getTime());
```

- Getter than and equals

```js
//date.js
const isAfterDate = (dateA, dateB) => dateA > dateB;
const isBeforeDate = (dateA, dateB) => dateA < dateB;

//main.js
console.log(new Date(2021, 08, 11) > new Date(2021, 08, 10));
console.log(new Date(2021, 08, 09) > new Date(2021, 08, 10));
console.log(
  new Date(2021, 08, 10).toISOString() === new Date(2021, 08, 10).toISOString()
);
```

**Read more:** <https://decipher.dev/30-seconds-of-typescript/docs/isSameDate>

- Sort array by date

```js
const users = [
  { name: "1", dob: "1989/8/26" },
  { name: "2", dob: "1989/8/23" },
  { name: "3", dob: "1989/8/25" },
];

const sortedUsers = users.sort(
  ({ dob: dob1 }, { dob: dob2 }) =>
    new Date(dob1).getTime() - new Date(dob2).getTime()
);
console.log(sortedUsers);

/**
[
  { name: '2', dob: '1989/8/23' },
  { name: '3', dob: '1989/8/25' },
  { name: '1', dob: '1989/8/26' }
]
**/
```

- Humanize duration

```js
//date.js

exports.formatDuration = (ms) => {
  ms = Math.abs(ms);
  const time = {
    day: Math.floor(ms / 86400000),
    hour: Math.floor(ms / 3600000) % 24,
    minute: Math.floor(ms / 60000) % 60,
    second: Math.floor(ms / 1000) % 60,
    millisecond: Math.floor(ms) % 1000,
  };
  return Object.entries(time)
    .filter((val) => val[1] !== 0)
    .map(([key, val]) => `${val} ${key}${val !== 1 ? "s" : ""}`)
    .join(", ");
};
// main.js

console.log(formatDuration(34325055574));
```

**Read more:** <https://decipher.dev/30-seconds-of-typescript/docs/formatDuration>

## References

- <https://decipher.dev/30-seconds-of-typescript>
- <https://stackoverflow.com/questions/tagged/javascript+date>
- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat>
- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date>
- <https://www.w3schools.com/jsref/jsref_obj_date.asp>

