0

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?

9
  • So many options? The formats depend on which country the script is intended for. In English speaking world 12/1/1994 would usually mean Dec 1st, in some other countries it would be Jan 12th. So decide what date formats are common in your country and then regexp would be the best solution, I think. Commented Jun 17, 2014 at 21:31
  • I can think of dozens... I will try regexp Commented Jun 17, 2014 at 21:37
  • You can listen to the field using jQuery and split the spaces or characters you need, either create a mask or read the values and convert them based on your needs by that I mean convert 1 dec 1994 to 01/12/1994 you need to compare the values using an array() with javascript. Commented Jun 17, 2014 at 21:41
  • @ncohen Maybe good way could be replacing all symbols except 0-9 and a-z by space. When you split it by space then, it should create array of 3 elements. If one of the elements contains st, nd, rd or th - use it as a day. If one of the elements is letters-only, convert it to number and use it as a month. If one of the elements has 4 digits, use it as year. If none of them applies, use 1st element as month, second as day and 3rd as year. ETC... Commented Jun 17, 2014 at 21:53
  • @user2781994 Interesting... I will try that and use regexp. I also need to track when the input loses focus to change the value. BTW do you know how can I catch that? Commented Jun 17, 2014 at 21:55

1 Answer 1

2

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 ;)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.