Dates come in multiple formats:
Let’s get started by defining some variables to use in our examples
1const UNIX = 1481884441
2const ISO8601 = '2016-11-04T17:39:59.910Z'
3const invalidISO = '2016-31-31T17:39:59.910Z'
4const invalidDate = '2016/31/31'
5
6let date = Date.now() // Date.now() is faster than new Date()
Date.now()
vs. new Date()
Note that while Date.now()
is faster in performance than new Date()
, it gives a number value (epoch/unix time) instead of a Date object. So, you won’t be able to do something like Date.now().toLocaleTimeString()
because .toLocaleDateString()
only works on a Date object.
1typeof new Date() // "object"
2typeof Date.now() // "number"
3
4new Date().toLocaleDateString() // "28/03/2017"
5Date.now().toLocaleDateString() // Uncaught TypeError: Date.now(...).toLocaleDateString is not a function
You can use moment.js
and it’s isValid()
to see if the value is a valid date
1import moment from 'moment'
2
3moment.unix(UNIX).isValid() // check unix timestamps
4moment(ISO8601).isValid() // check date strings
Validating dates with vanilla JS is a bit tricky because of the multiple date fromats.
You can use Date.parse()
to check if the value is a valid date string. It gives the Unix timestamp if valid date string and NaN
if the string is unrecognized or contains illegal date values (e.g. February 31?)
To check is the output is Nan, you can use the isNaN
function (Date.prase(x) === NaN
doesn’t work for some reason)
1function isDateString (x) {
2 return isNaN(Date.parse(x)) ? false : true
3}
4
5isDateString(UNIX) ? console.info('hell yeah') : console.info('neh') // "neh"
6isDateString(ISO8601) ? console.info('hell yeah') : console.info('neh') // "hell yeah"
Date.parse()
is no good for validating Unix timestamps.
The trick is to convert the timestamp to date object first and validate that. Since JS works in milliseconds, you need to convert the timestamp (seconds) to milliseconds first (by multiplying it with 1000)
1function isUnixTimestamp (x) {
2 let timestamp = x * 1000
3 let time = new Date(timestamp)
4
5 return isNaN(Date.parse(time)) ? false : true
6}
7
8isUnixTimestamp(UNIX) ? console.info('timestamp') : console.info('neh') // "timestamp"
9isUnixTimestamp(ISO8601) ? console.info('timestamp') : console.info('neh') // "neh"
10isUnixTimestamp(invalidISO) ? console.info('timestamp') : console.info('neh') // "neh"
We can combine both of the above function to make a isValidDate
function.
1function isValidDate (x) {
2 return isDateString(x) || isUnixTimestamp(x) ? true : false
3}
4
5sValidDate(UNIX) ? console.info('valid date') : console.info('nope') // "valid date"
6isValidDate(ISO8601) ? console.info('valid date') : console.info('nope') // "valid date"
7isValidDate(invalidISO) ? console.info('valid date') : console.info('nope') // "nope"
8isValidDate(invalidDate) ? console.info('valid date') : console.info('nope') // "nope"
9isValidDate('abc') ? console.info('valid date') : console.info('nope') // "nope"
Note that there are going to be some edge cases with this:
1// 123 is a valid date
2isValidDate('123') ? console.info('valid date') : console.info('nope') // "valid date" 123 is a valid timestamp!
3
4// Checking for 31st of Feb (this will give different values based on locale date format)
5isValidDate('2016/02/31') ? console.info('valid date') : console.info('nope') // "valid date"
6isValidDate('2016/31/02') ? console.info('valid date') : console.info('nope') // "nope"
toLocaleString()
let’s you format a date using the locale settings. Locales let you specify the language whose formatting conventipons should be used. Different locales have different conventions for writing dates, for example en-US
uses 12-hour time with AM/PM while en-GB
uses 24-hour format. en-US
has month first and then date, while en-gb
has date first and then month. You can customize the format for the locale string.
1console.info('en-us', date.toLocaleString('en-us')) // "1/10/2017, 3:29:15 PM"
2console.info('en-GB', date.toLocaleString('en-GB')) // "10/01/2017, 15:29:15"
3console.info('ar-EG', date.toLocaleString('ar-EG')) // "١٠/١/٢٠١٧ ٣:٣٢:٣٣ م"
4console.info('de-DE', date.toLocaleString('de-DE')) // "10.1.2017, 15:32:33"
You can further customize the locale string by passing it an options argument (object).
1let localeStringOptions = {
2 weekday: 'long',
3 month: 'long',
4 day: 'numeric',
5 year: 'numeric'
6}
7
8console.info('en-us', date.toLocaleString('en-us', localeStringOptions)) // "Tuesday, January 10, 2017"
9console.info('en-GB', date.toLocaleString('en-GB', localeStringOptions)) // "Tuesday, 10 January 2017"
10console.info('ar-EG', date.toLocaleString('ar-EG', localeStringOptions)) // "الثلاثاء، ١٠ يناير، ٢٠١٧"
11console.info('de-DE', date.toLocaleString('de-DE', localeStringOptions)) // "Dienstag, 10. Januar 2017"
Furthermore, you can detect the locale of the browser with navigator.language
and navigator.userLanguage
, like this:
1let locale = navigator.language || navigator.userLanguage
2
3console.info('month', date.toLocaleString(locale, {month: 'long'})) // "January"
For example, get the month name (e.g. Jan) using toLocaleString
1let time = new Date('2016-11-04T17:39:59.910Z')
2
3let localeString = time.toLocaleString('en-US', {month: 'short'})
4
5console.info(localeString) // Nov
Date.now()
is faster than new Date()
since you don’t have to instantiate a new Date
object. stackoverflow jsperf