I'm using Pikaday.js like so:
new Pikaday({
field: document.getElementById('top-banner-datepicker'),
minDate: new Date()
I know that the answer lies in this example from the documentation:
var picker = new Pikaday({
field: document.getElementById('datepicker'),
format: 'D/M/YYYY',
toString(date, format) {
// you should do formatting based on the passed format,
// but we will just return 'D/M/YYYY' for simplicity
const day = date.getDate();
const month = date.getMonth() + 1;
const year = date.getFullYear();
return `${day}/${month}/${year}`;
},
parse(dateString, format) {
// dateString is the result of `toString` method
const parts = dateString.split('/');
const day = parseInt(parts[0], 10);
const month = parseInt(parts[1], 10) - 1;
const year = parseInt(parts[2], 10);
return new Date(year, month, day);
}
});
But I can't figure out how to use full day (Monday, Tuesday, Wednesday, etc) and full month names (January, February, etc) instead of the abbreviations (Mon, Tue, Wed... Jan, Feb, Mar... etc)
I don't want to use Moment.JS as it's a giant dependency.
Any help much appreciated!
Thank you
I'm using Pikaday.js like so:
new Pikaday({
field: document.getElementById('top-banner-datepicker'),
minDate: new Date()
I know that the answer lies in this example from the documentation:
var picker = new Pikaday({
field: document.getElementById('datepicker'),
format: 'D/M/YYYY',
toString(date, format) {
// you should do formatting based on the passed format,
// but we will just return 'D/M/YYYY' for simplicity
const day = date.getDate();
const month = date.getMonth() + 1;
const year = date.getFullYear();
return `${day}/${month}/${year}`;
},
parse(dateString, format) {
// dateString is the result of `toString` method
const parts = dateString.split('/');
const day = parseInt(parts[0], 10);
const month = parseInt(parts[1], 10) - 1;
const year = parseInt(parts[2], 10);
return new Date(year, month, day);
}
});
But I can't figure out how to use full day (Monday, Tuesday, Wednesday, etc) and full month names (January, February, etc) instead of the abbreviations (Mon, Tue, Wed... Jan, Feb, Mar... etc)
I don't want to use Moment.JS as it's a giant dependency.
Any help much appreciated!
Thank you
Share Improve this question asked Sep 2, 2020 at 22:12 HandiworkNYC.HandiworkNYC. 11.1k25 gold badges95 silver badges156 bronze badges 03 Answers
Reset to default 7 +500If you wish to format the datepicker field you could use toLocaleString().
For example if you want to get October instead of Oct:
date.toLocaleString('default', {
month: 'long' // use localestring month to get the long month
});
And if you want to get Sunday instead of Sun:
date.toLocaleString('default', { // use localestring weekday to get the long day
weekday: 'long'
});
Example snippet:
var picker = new Pikaday({
field: document.getElementById('datepicker'),
firstDay: 1,
minDate: new Date(),
maxDate: new Date(2020, 12, 31),
yearRange: [2000, 2020],
format: 'D-M-YYYY',
toString(date, format) {
console.log(date.toLocaleString('default', {
weekday: 'short' // use localestring weekday to get the short abbv of day
}));
console.log(date.toLocaleString('default', {
month: 'short' // use localestring weekday to get the short abbv of month
}));
// you should do formatting based on the passed format,
// but we will just return 'D/M/YYYY' for simplicity
const day = date.getDate();
const daylong = date.toLocaleString('default', { // use localestring weekday to get the long day
weekday: 'long'
});
const month = date.getMonth() + 1;
const monthlong = date.toLocaleString('default', {
month: 'long' // use localestring month to get the long month
});
const year = date.getFullYear();
return `${daylong}, ${monthlong}, ${day} ${year}`; // just format as you wish
}
});
#datepicker {
width: 200px;
}
<link href="https://pikaday./css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday./pikaday.js"></script>
<label for="datepicker">Date:</label>
<input type="text" id="datepicker">
Pikaday Parsing
It's usually pretty easy getting dates into the correct format, but the tricky part usually is getting a date from a string. There's this warning in the Pikaday Read Me:
Be careful, though. If the formatted string that you return cannot be correctly parsed by the
Date.parse
method (or bymoment
if it is available), then you must provide your ownparse
function in the config. This function will be passed the formatted string and the format:
parse(dateString, format = 'YYYY-MM-DD')
Using Date.parse
, can yield irregular results. This is where moment.js
es in handy as it can handle a variety of formats. The parsing function is used when a person directly types into the input field and maybe elsewhere.
Two approaches could involve using lightweight alternative to moment.js, or a custom formatter.
Approach 1: Lightweight Alternatives
You can search for moment.js alternatives. I found this repo that lists a few. For this example, I chose luxon, as it seems to be pretty small. You can see all the token it supports here: https://moment.github.io/luxon/docs/manual/parsing.html#table-of-tokens
To help out with parsing, I added this bit, which strips out weekday parsing, just in case if the weekday doesn't match the actual date:
if (format.startsWith('EEEE ')) {
format = format.split(' ').slice(1).join(' ');
dateString = dateString.split(' ').slice(1).join(' ');
}
Here's a working snippet:
var picker = new Pikaday({
field: document.getElementById('datepicker'),
format: 'EEEE LLLL d, yyyy',
toString(date, format) {
return luxon.DateTime.fromJSDate(date).toFormat(format);
},
parse(dateString, format) {
if (format.startsWith('EEEE ')) {
format = format.split(' ').slice(1).join(' ');
dateString = dateString.split(' ').slice(1).join(' ');
}
return luxon.DateTime.fromFormat(dateString, format).toJSDate();
}
});
div {
position: absolute;
bottom: 0;
}
#datepicker {
width: 250px;
}
<link href="https://pikaday./css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday./pikaday.js"></script>
<script src="https://moment.github.io/luxon/global/luxon.min.js"></script>
<div><label for="datepicker">Date:</label>
<input type="text" id="datepicker">
</div>
Approach 2: Custom Formatter
For this answer I'll just use the format that you're asking for, but it gets tricky to parse a variety of formats.
Custom Names
To get custom names for months, you can just hard code them in:
var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
Alternatively, since you want normal names, you can just programmatically generate them using Intl.DateTimeFormat. This is also useful if you want to have the months and weekdays show up in the user's locale:
var monthFormatter = new Intl.DateTimeFormat([], { month: 'long' });
var months = [... new Array(12)].map((d, i) => monthFormatter.format(new Date(2020, i, 1)));
var dayFormatter = new Intl.DateTimeFormat([], { weekday: 'long' });
var days = [... new Array(7)].map((d, i) =>dayFormatter.format(new Date(2020, 1, 2 + i)));
To access the names, you just use the corresponding index (remember that they're zero based though)
console.log(months[new Date().getMonth()]); // current month
console.log(days[new Date().getDay()]); // current day
Thus your custom format function looks something like this:
toString(date, format) {
// you should do formatting based on the passed format,
// but we will just return 'D/M/YYYY' for simplicity
const day = date.getDate();
const year = date.getFullYear();
const weekday = date.getDay();
const month = date.getMonth(); // remember, this is zero based!
return `${days[weekday]} ${months[month]} ${day}, ${year}`;
},
Date Parsing
Here's a custom tailored parsing function for the above format Weekday Month Day, Year
:
parse(dateString, format) {
// split the string into the parts separated by a space
const parts = dateString.trim().split(' ');
var day, month, year, startIndex;
if (parts.length >= 3) {
if (parts.length >= 4) {
// if there's four parts, assume the first part is the weekday, which we don't need to use to convert it to a date
startIndex = 1; // skip the weekday
} else {
// if there's only three parts, assume that the weekday was omitted
startIndex = 0;
}
// look up the month from our prebuilt array. If it isn't found, it'll return -1, otherwise it will return the (zero based) numerical month.
month = months.indexOf(parts[startIndex]);
day = parts[startIndex + 1];
// if there's a ma after the day, remove it
if (day.endsWith(',')) {
day = day.substring(0, day.length - 1);
}
day = +day; // convert the string into a number
year = +parts[startIndex + 2]; // convert the string year into a number
}
if (parts.length < 3 // there is less than 3 parts
|| month === -1 // the month wasn't found
|| isNaN(day) // the day isn't a number
|| isNaN(year)) { // the year isn't a number
return Date.parse(dateString); // fall back to default Date parsing
}
return new Date(year, month, day);
}
All together, it looks like this:
var monthFormatter = new Intl.DateTimeFormat([], { month: 'long' });
var months = [... new Array(12)].map((d, i) => monthFormatter.format(new Date(2020, i, 1)))
var dayFormatter = new Intl.DateTimeFormat([], { weekday: 'long' });
var days = [... new Array(7)].map((d, i) =>dayFormatter.format(new Date(2020, 1, 2 + i)))
// Alternatively you can just hard code these:
// var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
// var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
var picker = new Pikaday({
field: document.getElementById('datepicker'),
format: 'D/M/YYYY',
toString(date, format) {
// you should do formatting based on the passed format,
// but we will just return 'D/M/YYYY' for simplicity
const day = date.getDate();
const year = date.getFullYear();
const weekday = date.getDay();
const month = date.getMonth(); // remember, this is zero based!
return `${days[weekday]} ${months[month]} ${day}, ${year}`;
},
parse(dateString, format) {
// split the string into the parts separated by a space
const parts = dateString.trim().split(' ');
var day, month, year, startIndex;
if (parts.length >= 3) {
if (parts.length >= 4) {
// if there's four parts, assume the first part is the weekday, which we don't need to use to convert it to a date
startIndex = 1; // skip the weekday
} else {
// if there's only three parts, assume that the weekday was omitted
startIndex = 0;
}
// look up the month from our prebuilt array. If it isn't found, it'll return -1, otherwise it will return the (zero based) numerical month.
month = months.indexOf(parts[startIndex]);
day = parts[startIndex + 1];
// if there's a ma after the day, remove it
if (day.endsWith(',')) {
day = day.substring(0, day.length - 1);
}
day = +day; // convert the string into a number
year = +parts[startIndex + 2]; // convert the string year into a number
}
if (parts.length < 3 // there is less than 3 parts
|| month === -1 // the month wasn't found
|| isNaN(day) // the day isn't a number
|| isNaN(year)) { // the year isn't a number
return Date.parse(dateString); // fall back to default Date parsing
}
return new Date(year, month, day);
}
});
div {
position: absolute;
bottom: 0;
}
#datepicker {
width: 250px;
}
<link href="https://pikaday./css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday./pikaday.js"></script>
<div><label for="datepicker">Date:</label>
<input type="text" id="datepicker">
</div>
Not going to write a book about it, because such default formats can be acplished with Date
, in particular method toLocaleDateString()
, where long
is the non-abbreviated weekday/month:
dateLocale: 'en-US',
dateOptions: {weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'},
toString(date, format) {
return date.toLocaleDateString(this.dateLocale, this.dateOptions);
},
Even if the formatting possibilities are rather limited alike that,
the advance still is, that supporting multi-locale is no problem.