DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 968,547 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Introducing a handy JavaScript date formatting function.
riversun
riversun

Posted on • Updated on

Introducing a handy JavaScript date formatting function.

I created A function to format the date (Date object) with a pattern like yyyy-MM-dd'T'HH:mm:ssXXX in JavaScript.
With this function alone, ISO8601 format, RFC1123 format, time zone RFC822, etc. can be expressed.
Pattern specification is like Java's SimpleDateFormat.

Date formatting function

function formatDate(formatStr, date, opts) {

    if (!date) {
        date = new Date();
    }

    opts = opts || {};

    let _days = opts.days;

    if (!_days) {
        _days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
    }

    let _months = opts.months;

    if (!_months) {
        _months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    }

    const pad = (number, strDigits, isUnpad) => {
        const strNum = Math.abs(number).toString();
        if (!isUnpad && strNum.length > strDigits.length) {
            return strNum;
        } else {
            return ('0000' + strNum).slice(-strDigits.length);
        }
    };

    const timezone = (date, letter) => {
        const chunk = [];
        const offset = -date.getTimezoneOffset();
        chunk.push(offset === 0 ? 'Z' : offset > 0 ? '+' : '-');//add Z or +,-
        if (offset === 0) return chunk;
        chunk.push(pad(Math.floor(offset / 60), '00'));//hour
        if (letter === 'X') return chunk.join('');
        if (letter === 'XXX') chunk.push(':');
        chunk.push(pad((offset % 60), '00'));//min
        return chunk.join('');
    };

    const DELIM = '\0\0';
    const escapeStack = [];

    const escapedFmtStr = formatStr.replace(/'.*?'/g, m => {
        escapeStack.push(m.replace(/'/g, ''));
        return `${DELIM}${escapeStack.length - 1}${DELIM}`;
    });

    const formattedStr = escapedFmtStr
        .replace(/y{4}|y{2}/g, m => pad(date.getFullYear(), m, true))
        .replace(/M{3}/g, m => _months[date.getMonth()])
        .replace(/M{1,2}/g, m => pad(date.getMonth() + 1, m))
        .replace(/M{1,2}/g, m => pad(date.getMonth() + 1, m))
        .replace(/d{1,2}/g, m => pad(date.getDate(), m))
        .replace(/H{1,2}/g, m => pad(date.getHours(), m))
        .replace(/h{1,2}/g, m => {
            const hours = date.getHours();
            return pad(hours === 0 ? 12 : hours > 12 ? hours - 12 : hours, m);
        })
        .replace(/a{1,2}/g, m => date.getHours() >= 12 ? 'PM' : 'AM')
        .replace(/m{1,2}/g, m => pad(date.getMinutes(), m))
        .replace(/s{1,2}/g, m => pad(date.getSeconds(), m))
        .replace(/S{3}/g, m => pad(date.getMilliseconds(), m))
        .replace(/[E]+/g, m => _days[date.getDay()])
        .replace(/[Z]+/g, m => timezone(date, m))
        .replace(/X{1,3}/g, m => timezone(date, m));

    const unescapedStr = formattedStr.replace(new RegExp(`${DELIM}\\d+${DELIM}`, 'g'),
        m => {
            const unescaped = escapeStack.shift();
            return unescaped.length > 0 ? unescaped : '\'';
        });

    return unescapedStr;
}

Call function like as follows

const date = new Date();

//Format with patterns
console.log(formatDate("MMM dd, yyyy",date));
//->Feb 17, 2020

console.log(formatDate("MM/dd/yyyy",date));
//->02/17/2020

console.log(formatDate("EEE, MMM d, ''yy",date));
//->Mon, Feb 17, '20

console.log(formatDate("h:mm a",date));
//->8:46 PM

console.log(formatDate("hh 'o''''clock' a, Z",date));
//->08 o'clock PM, -0600

//ISO8601 format
console.log(formatDate("yyyyMMdd'T'HHmmssXX",date));
//->20200217T204746-0600

//ISO8601 format alt
console.log(formatDate("yyyy-MM-dd'T'HH:mm:ssXXX",date));
//->2020-02-17T20:47:46-06:00

//RFC1123(RFC822) format
console.log(formatDate("E, dd MMM yyyy HH:mm:ss Z",date));
//->Mon, 17 Feb 2020 20:47:46 -0600


The result is as follows:

Feb 17, 2020
02/17/2020
Mon, Feb 17, '20
8:47 PM
08 o'clock PM, -0600
20200217T204746-0600
2020-02-17T20:47:46-06:00
Mon, 17 Feb 2020 20:47:46 -0600
Mon, Feb 17, '20
Hello! It's 20:47:46.

Pattern of the date

The following examples show how date and time patterns are interpreted.
The given date and time are 2018-07-17 12:08:56 local time in Tokyo/Japan time zone.

Letter(s) Date or Time Component Examples
yyyy Year 2018
yy 18
M Month in year 7
MM 07
MMM Month name Jul
d Day in month 17
dd 17
a Am/pm marker PM
H Hour in day (0-23) 12
HH 12
E day of week Tue
h Hour in am/pm (1-12) 12
hh 12
m Minute in hour 8
mm 08
s Second in minute 56
ss 56
S Millisecond 789
Z Timezone(RFC822) +0900
X Timezone(ISO8601) +09
XX +0900
XXX +09:00
' ' Strings(Escaped)
'' Single Quote

Pattern examples

Format String Example
yyyyMMdd'T'HHmmssXX
(ISO 8601)
20180717T120856+0900
yyyy-MM-dd'T'HH:mm:ssXXX
(ISO 8601)
2018-07-17T12:08:56+09:00
E, dd MMM yyyy HH:mm:ss Z Tue, 17 Jul 2018 12:08:56 +0900
yyyy.MM.dd 'at' hh:mm:ss Z 2018.07.17 at 12:08:56 +0900
EEE, MMM d, ''yy Tue, Jul 17, '18
h:mm a 12:08 PM
hh 'o''''clock' a, X 12 o'clock PM, +09
yyyyMMddHHmmssSSS 20180717120856789

Live demo

Repository

The library version is in the following repository for ease of use.

https://github.com/riversun/simple-date-format

Top comments (1)

Collapse
 
luispunq profile image
Luispunq

Dude this saved me a bunch of hours,, cheers

Visualizing Promises and Async/Await 🀯

async await

☝️ Check out this all-time classic DEV post