Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pikaday JS How to use full day and month names for input format without moment js

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

enter image description here

like image 325
HandiworkNYC.com Avatar asked Sep 02 '20 22:09

HandiworkNYC.com


People also ask

How do I format a date in moment JS?

Formatting By default, dates are formatted and parsed using standard JavaScript Date object. If Moment.jsis available in scope, it will be used to format and parse input values. You can pass an additional formatoption to the configuration which will be passed to the momentconstructor.

What is the best way to get the date in pikaday?

picker.toString('YYYY-MM-DD') Returns the selected date in a string format. If Moment.jsexists (recommended) then Pikaday can return any format that Moment understands. You can also provide your own toStringfunction and do the formatting yourself.

How do I change the date range in pikaday?

Change the year being viewed. picker.setMinDate() Update the minimum/earliest date that can be selected. picker.setMaxDate() Update the maximum/latest date that can be selected. picker.setStartRange() Update the range start date. For using two Pikaday instances to select a date range. picker.setEndRange() Update the range end date.

What format does pikaday return?

If Moment.jsexists (recommended) then Pikaday can return any format that Moment understands. You can also provide your own toStringfunction and do the formatting yourself. Read more in the formattingsection.


Video Answer


2 Answers

If 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.com/css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday.com/pikaday.js"></script>
<label for="datepicker">Date:</label>
<input type="text" id="datepicker">
like image 60
Mukyuu Avatar answered Oct 16 '22 10:10

Mukyuu


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 by moment if it is available), then you must provide your own parse 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 comes 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.com/css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday.com/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 comma 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 comma 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.com/css/pikaday.css" rel="stylesheet" />
<script src="https://pikaday.com/pikaday.js"></script>
<div><label for="datepicker">Date:</label>
<input type="text" id="datepicker">
</div>
like image 2
Steve Avatar answered Oct 16 '22 09:10

Steve