简体   繁体   中英

Clever time formatting with JavaScript

I need help writing a little Regular Expression to replace integers into a time format string in a text input field.

In my form: I have a text input field where I'm supposed to write numbers. And when I write a number: I want a piece of JavaScript to convert it to a human-friendly, readable time when the input field loses focus. The thing that makes this "Clever" is that I want to be able to write as little as absolutely possible: And have it transform to the most appropriate time corresponding to my number.

Let me give you a few examples. If I write:

7 it would resolve to 07:00
15 it would resolve to 15:00
93 it would resolve to 09:30
1945 it would resolve to 19:45
143 it would resolve to 14:30
... And so on ...

I want it to do this replacement after the input field loses focus ( onblur -event)

Also. I want to have a 0 prefix for night hours. Like this:

015 = 00:15
 03 = 00:30
012 = 00:12 
... And so on ...

I begun writing if statements to do this, but I stopped dead in my tracks because I realized it would take so many if statements, and would not be very reliable. I feel like Regular Expressions would be much smarter since it compacts my script and makes loading time quicker. I grasp the basics of Regular Expressions, but I don't know how to write a clever one for this purpose.

This is what my code got to before I decided to drop it:

var elem = document.getElementById("incidentHourStart-" + row);

if (elem.value.length === 1) {
    // Must be a whole hour (0-9)
} else if (elem.value.length === 2) {
    // Can be either two digits hour (10-23) or hour + whole minute (73: 07:30)
    if (parseInt(elem.value) >= 10 && parseInt(elem.value) <= 23) {
        // Two digits, whole hour (10-23)
    } else {
        // First digit is hour, and last one is whole minute (10, 20, 30, 40, 50)   
    }

} else if (elem.value.length === 3) {
    // First digit must be an hour value, middle digit is also hour if it is lower than 23, last digit is then always whole minutes
    if (parseInt(elem.value) >= 10 && parseInt(elem.value) <= 23) {
        // Two digits, whole hour (10-23)
    } else {
        // First digit is hour, and last one is whole minute (10, 20, 30, 40, 50)   
    }
} else if (elem.value.length === 4) {
    // First two digits must be an hour value, last digits is then fine selected minutes

}

As you can see: It looks very ugly!


UPDATE:

As stated in the comments: People have found my rules a little confusing. So here is the pseudo code of rules I want it to follow. If this can be put into a Regex in a clever way: Then awesome! If not: I will write out the if/else blocks, or split the Regex up into parts as suggested.

If text-length is equal to 1
    Resolve as whole hour between 0-9

    Examples:
        2 = 02:00
        8 = 08:00
        5 = 05:00

If text-length is equal to 2 AND number is between 10 and 23
    Resolve as whole hour between 10-23

    Examples:
        15 = 15:00
        11 = 11:00
        22 = 22:00

If text-length is equal to 2 AND number is NOT between 10 and 23
    Resolve as whole hour and minutes incremented by 10's (10, 20, 30, 40, 50)

    Examples:
        73 = 07:30
        24 = 02:40
        95 = 09:50

If text-length is equal to 3 AND first two numbers are between 10 and 23
    Resolve two first digits as hours and last digit as minutes incremented by 10's (10, 20, 30, 40, 50)

    Examples:
        133 = 13:30
        195 = 19:50
        111 = 11:10
        162 = 16:20

If text-length is equal to 3 AND first two numbers are NOT between 10 and 23
    Resolve first digit as whole hour, and last two as minutes.

    Examples:
        225 = 02:25
        922 = 09:22
        557 = 05:57
        451 = 04:51

If text-length is equal to 1 AND first digit is equal to 0
    Resolve as mid-night

    Example:
        0 = 00:00

If text-length is equal to 2 AND first digit is equal to 0
    Resolve as mid-night + minutes incremented by 10's (10, 20, 30, 40, 50)

    Examples:
        02 = 00:20
        05 = 00:50
        03 = 00:30

If text-length is equal to 3 AND first digit is equal to 0
    Resolve as mid-night + full minutes.

    Examples:
        024 = 00:24
        011 = 00:11
        056 = 00:56

If text-length is equal to 4
    Resolve as regular minutes and hours without the colon (:)

    Examples:
        1524 = 15:24
        2211 = 22:11

Don't make it harder on yourself than you need. Simply put; don't do this in one regular expression. Also don't forget to trim your input before using RegEx.

First of all check the zero-prefixed one, something like:

^0(\d+)$

Then if that doesn't match, do the check for the normal numbering and split it with the capture groups however you want:

^([^0]\d{1,3})$ // Can do negative lookbehind here, but I left it simple in this case

Regular expressions are often misused to solve a bigger problem in one pattern. It's much better to split logic if the situation asks for it. Don't overcomplicate code. It will break whoever needs to read it later's brain.

I have found a solution and had it deployed for about 1.5 months now. And so far: It works great. My co-workers love this functionality, and really saves up a lot of time! So far: No faults have been reported to me.


So here is what I did:

I bascially re-wrote my pseudo-code into actual JavaScript code using if/else blocks as suggested in the question's comments. I stuck it all into a function that I call from an onblur event on the input fields. Like this:

<input type="text" id="incidentHourStart-1" onblur="resolveTimeField(1);">

So the formatting occurs as soon as the input field loses focus.

Here is what my function looks like:

function resolveTimeField(row) {
    var elem = document.getElementById("incidentHourStart-" + row);

    if (elem.value.length === 1) {

        // Must be a whole hour (0-9)
        elem.value = "0" + elem.value + ":00";

    } else if (elem.value.length === 2) {

        // Can be either two digits hour (10-23) or hour + whole minute (73: 07:30)
        if (parseInt(elem.value) >= 10 && parseInt(elem.value) <= 23) {
            // Two digits, whole hour (10-23)
            elem.value = elem.value + ":00";
        } else {
            // First digit is hour, and last one is whole minute (10, 20, 30, 40, 50)

            var hours = elem.value.substring(0, 1);
            var minutes = elem.value.substring(1, 2);
            elem.value = "0" + hours + ":" + minutes + "0";

        }
    } else if (elem.value.length === 3) {

        // First digit must be an hour value, middle digit is also hour if it is lower than 23, last digit is then always whole minutes
        var firstDigits = elem.value.substring(0, 2);

        if (parseInt(firstDigits) >= 10 && parseInt(firstDigits) <= 23) {

            // 3 digits, first two are hours, and last digit is minutes incremented by 10's
            var hours = elem.value.substring(0, 2);
            var minutes = elem.value.substring(2, 3);
            elem.value = hours + ":" + minutes + "0";

        } else {

            // First digit is hour, and last two is full minutes
            var hours = elem.value.substring(0, 1);
            var minutes = elem.value.substring(1, 3);
            elem.value = "0" + hours + ":" + minutes;

        }
    } else if (elem.value.length === 4) {

        // First two digits must be an hour value, last digits is then fine selected minutes
        var hours = elem.value.substring(0, 2);
        var minutes = elem.value.substring(2, 4);
        elem.value = hours + ":" + minutes;

    }
}

Here is a JSFiddle if you want to test out the code for yourself

My function takes one parameter referenced as row . This is because the fields I am working with lays within a dynamic table that lets my co-workers register more data in one go.

Currently it does not have any forms of input validation that checks if the inserted value is valid. So you could write something like 999 into the field and have it resolve to 09:99 . This is not a critical feature for our environment, but I can imagine it would be fairly easy to implement shall it be required. I will update this post if I ever implement such a validation feature in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM