使用 JavaScript 巧妙地格式化时间

Clever time formatting with JavaScript

我需要帮助编写一些正则表达式来将整数替换为文本输入字段中的时间格式字符串。

在我的表单中:我有一个文本输入字段,我应该在其中输入数字。当我写一个数字时:我想要一段 JavaScript 在输入字段失去焦点时将其转换为人性化的、可读的时间。之所以这样 "Clever" 是因为我希望能够尽可能少地写:并让它转换为与我的数字相对应的最合适的时间。

让我举几个例子。如果我写:

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 ...

我希望它在输入字段失去焦点后执行此替换(onblur-事件)

还有。我想在夜间使用 0 前缀。像这样:

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

我开始编写 if 语句来执行此操作,但我停了下来,因为我意识到它需要很多 if 语句,而且不太可靠。我觉得正则表达式会更聪明,因为它压缩了我的脚本并使加载时间更快。我掌握了正则表达式的基础知识,但我不知道如何为此目的编写一个巧妙的表达式。

在我决定放弃之前我的代码是这样的:

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

}

如你所见:非常难看!


更新:

如评论中所述:人们发现我的规则有些混乱。所以这是我希望它遵循的规则的伪代码。如果可以巧妙地将其放入正则表达式中:那就太棒了!如果没有:我会写出 if/else 块,或者按照建议将正则表达式拆分成多个部分。

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

不要让自己变得比你需要的更难。简单的说;不要在一个正则表达式中执行此操作。在使用 RegEx 之前不要忘记 trim 您的输入。

首先检查零前缀的,比如:

^0(\d+)$

然后,如果不匹配,请检查正常编号并将其与您想要的捕获组分开:

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

正则表达式经常被误用在一种模式中解决更大的问题。如果情况需要,最好拆分逻辑。不要使代码过于复杂。以后想看的人会脑残。

我找到了一个解决方案,现在已经部署了大约 1.5 个月。到目前为止:效果很好。我的同事喜欢这个功能,真的节省了很多时间!到目前为止:没有向我报告任何故障。


这就是我所做的:

我基本上按照问题评论中的建议使用 if/else 块将我的伪代码重写为实际的 JavaScript 代码。我将它全部插入到一个函数中,该函数是我从输入字段上的 onblur 事件调用的。像这样:

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

因此,一旦输入字段失去焦点,就会进行格式化。

我的函数如下所示:

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;

    }
}

这里有 JSFiddle 如果您想自己测试代码

我的函数采用一个参数引用为 row。这是因为我正在使用的字段位于动态 table 中,让我的同事可以一次性注册更多数据。

目前它没有任何形式的输入验证来检查插入的值是否有效。因此,您可以在字段中写入类似 999 的内容,并将其解析为 09:99。这对我们的环境来说不是一个关键特性,但我可以想象如果需要它会很容易实现。如果我将来实现这样的验证功能,我会更新这个 post。