Nate
Nate

Reputation: 7856

HTML - Custom input date format

I would like to build an input date in html with automatic formatting. For example, if I write '1 dec 1994' or '12/1/1994' it will automatically detect that it's a date and will reformat it: '12.1.1994' and create a date object: exactly what does excel.

I don't want to build it myself because it seems too complicated and there are too many options so do you know any solution?

Upvotes: 0

Views: 1772

Answers (1)

user2781994
user2781994

Reputation: 469

Here is complex function, which should convert many common date strings to day, month and year integers. This definitely has some weak spots, so fell free to comment any errors or ideas for upgrade.

The idea behind this script was:

  1. Actual date information comes from digits and letters only
    • Solution: Convert all additional symbols (dots, slashes, dashes) to spaces and eventually remove multiple spaces
  2. The step above should create string with 3 date parts divided by space
    • Solution: Split the date string by space -> having 3 parts separated, but which one is day, month and year?
  3. The part with 4 digits has to be the year (day or month will never have 4 digits)
  4. The part with 1 to 2 digits and st|nd|rd|th has to be the day
  5. The part with month name (jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) has to be the month
  6. If 2 parts are assigned to its variables, the third part has to belong to the one not-yet-set variable
  7. If only one or none variables is set by conditions above, assume YYYYMMDD or MMDDYYYY format is used
    • Solution: If first part of date has 4 digits, it has to be YYYYMMDD format, otherwise use MMDDYYYY

Define variables

  • el = the input where the date is typed
  • reg_day = matches 1 to 2 digits with case-insensitive suffix (1st, 2ND, 3Rd)
  • reg_month = matches any month name, ?: means that it is not remembered and the substring won't be in resulting array
  • reg_year = matches any 4-digit string

Code:

var el = document.getElementById("date_input"),
    reg_day = /\d{1,2}(st|nd|rd|th)/i,
    reg_month = /(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i.
    reg_year = /^\d{4}$/;

Add leading zero function

This function adds leading zero (if necessary) to day or month integer (returns string)

  1. Convert integer to string (since integer cannot have leading zeros)
  2. If its length is smaller than 2 (numbers 1 to 9), add "0" to it
  3. Return the string with the zero

Code:

function addZero(num) {
    var s = num.toString();
    while (s.length < 2) s = "0" + s;
    return s;
}

Convert functions

  1. If month is a word, find its 3-letter abbreviation and return the month number
  2. If month is valid number (01-12 or 1-12), parse it and return
  3. Else return null (unknown format)

Code:

function getMonth(month) {
    if(month.search(reg_month) > -1) {
        var month_name = month.match(reg_month)[0];
        return new Date(Date.parse(month_name + " 1, 2000")).getMonth() + 1;
    } else if(month.search(/^(0?[1-9]|1[0-2])$/) > -1) {
        return parseInt(month);
    }
    return null;
}

  1. Remove any letters (like st or th)
  2. If day is valid number (01-31 or 1-31), parse it and return
  3. Else return null (unknown format)

Code:

function getDay(day) {
    day = day.replace(/\D+/g, "")
    if(day.search(/^(0?[1-9]|[12][0-9]|3[01])$/) > -1) {
        return parseInt(day);
    }
    return null;
}

  1. If year is valid 4-digit number, parse it and return
  2. Else return null (unknown format)

Code:

function getYear(year) {
    if(year.search(reg_year) > -1) {
        return parseInt(year);
    }
    return null;
}

Onblur - when input loses focus

  • val = value of the date input
  • array = array of day, month, year values
    1. Replace all non digit or a-z characters by space
    2. Replace all multiple spaces with only one space
    3. Split the string by spaces (should give array of 3 elements)
  • data_not_used = array of indexes from array, which are not assigned by following for
  • declarations of day, month, year variables

Code:

el.onblur = function(){
    var val = el.value,
        array = val.replace(/[^A-Za-z0-9]/g, " ").replace(/ +(?= )/g, "").split(" "),
        data_not_used = [],
        day = null, month = null, year = null;
// fn continues below

  1. If array element is day with suffix, assign this to the day variable
  2. If array element is month name, assign its number to the month variable
  3. If array element is year, assign this to the year variable
  4. Else add array index to data_not_used

    (more in variables section and in getDay, getMonth and getYear functions)

Code:

// fn continues above
    for(var i=0; i < array.length; i++) {
        if(array[i].search(reg_day) > -1) {
            day = getDay(array[i]);
        } else if(array[i].search(reg_month) > -1) {
            month = getMonth(array[i]);
        } else if(array[i].search(reg_year) > -1) {
            year = getYear(array[i]);
        } else {
            data_not_used.push(i);
        }
    }
// fn continues below

  • If more than one of day, month, year missing:
    1. If first element in array contains 4 digits, assume YYYYMMDD format
    2. Else assume MMDDYYYY format
  • If only one of day, month, year missing, fill it with the remaining value

Code:

// fn continues above
    if(data_not_used.length > 1) {
        if(array[0].search(/\d{4}/) > -1) {
            year = getYear(array[0]);
            month = getMonth(array[1]);
            day = getDay(array[2]);
        } else {
            month = getMonth(array[0]);
            day = getDay(array[1]);
            year = getYear(array[2]);
        }
    }

    else if(data_not_used.length === 1) {
        var data = array[data_not_used[0]];
        if(day === null) day = getDay(data);
        else if(month === null) month = getMonth(data);
        else if(year === null) year = getYear(data);
    }
// fn continues below

  1. If all day, month, year are set, convert day & month to strings with leading zeros (1 to 01) and print them into console
  2. Else print error with values for debugging

Code:

// fn continues above
    if(day!==null && month!==null && year!==null) {
        console.log(addZero(month) + "/" + addZero(day) + "/" + year);
    } else {
        console.error("Date not valid: " + month + "/" + day + "/" + year);
    }
};

Don't forget to close onblur() function! Hopefully this was helpful ;)

Upvotes: 2

Related Questions