JS Regular Format Date and Time Automatically Fill 0

Question

We often encounter development tasks with time and date formatting, and there are also many tool conversion methods. For example, you need to convert the date format 2022-3-4 to 2022-03-04, That is, the single-digit month or day date is automatically prefixed with 0. It is also very easy to do it with the APIs of the third-party libraries of moment.js or dayjs. Let's take a look at the implementation by ourselves.

Solution One

Analysis:

Let's take a look at the conventional plan first. Take this 2022-3-4 date as an example. We first split the string according to - to get an array, and then identify the single-digit dates of 3 and 4 respectively, <10 Put 0 in front, otherwise do not operate.

Code:

function formatDate(str) {
  // Split according to - symbol
  return str
    .split("-")
    .map((item) => {
      // +item convert item string to number
      // Complete a prefix 0 when it is less than 10
      if (+item < 10) {
        return "0" + +item;
      }

      // No need to add 0 when it is greater than 10
      return item;
    })
    .join("-"); // Finally regroup back
}

// test
formatDate("2022-03-4"); // output '2022-03-04'

The above function only adapts to the simple conversion of 2022-3-4 to 2022-03-04, more complex date format or date and time format, such as 2022-3-4 1:2: 3 can't match yet. Moreover, we only recognize the format of - here. What if there are still 2022/3/4 and 2022.3.4?

Solution Two

Analysis:

Let's take a look at using regular expressions. Using regular expressions can not only simplify the code, but also make it easier to be compatible with more situations.

Our core idea is to use Lookahead assertion and Lookbehind assertion to identify the number in the middle of the date connection symbol, and then determine whether the number needs to be filled with 0. Before coding, let's get familiar with the usage of a few regular expressions.

  1. Lookahead assertion:(?=), and Lookbehind assertion:(?<=),

    To understand simply, it is

    // Lookahead assertion:
    A(?=B) //Find the A before B
    
    // Lookbehind assertion:
    (?<=B)A //Find the A behind B
    
    // Negative lookahead assertion:
    A(?!B) //Find A that is not B behind
    
    // Negative lookbehind assertion:
    (?<!B)A //Find A that is not B before
    

    We can use it here to identify the numbers between characters such as -, /, and .

  2. Word boundary: \b

    • Words refer to the characters that \w can match, namely numbers, uppercase and lowercase letters, and underscores [0-9a-zA-Z_]
    • Boundary refers to the position of the gap between the left and right characters

    Here we can use it to identify the number from - to the begin or end of the date. For example, in 2022-3-4 1:2:5, the gap after 4, the gap before 1, and the gap after 5 are all word boundaries.

  3. The replace method replaces the matched string: $&.

    After the single digit number is matched, 0 must be added. $& means the matched number, and 0 can be added by using 0$&.

Code:

// Use $& to match
function formatDate(str) {
  /*
        replace the first parameter regular

        (?<=\/|-|\.|:|\b)\d{1} is Lookbehind assertion, find / or - or . or : or word boundary or a number after T

        \d{1}(?=\/|-|\.|:|\b) is Lookahead assertion, find / or - or . or : or word boundary or a number before T

        replace the string matched by the second parameter "0$&" is prefixed with 0

    */
  return str.replace(/(?<=\/|-|\.|:|\b|T)\d{1}(?=\/|-|\.|:|\b|T)/g, "0$&");
}

// Use $1 to match
function formatDate(str) {
  /*
        The regular of the first parameter of replace is the same as above
        
        replace the second parameter is a function, and the first input parameter is the first parameter matched. You can add 0 in the function.
    */
  return str.replace(
    /(?<=\/|-|\.|:|\b|T)\d{1}(?=\/|-|\.|:|\b|T)/g,
    function ($1) {
      return "0" + $1;
    }
  );
}

// test
formatDate("2022-3-4 1:2:3"); // output '2022-03-04 01:02:03'
formatDate("2022/3/4"); // output '2022/03/04'
formatDate("2022.3.4"); // output '2022.03.04'
formatDate("2020/8/9T1:2:3"); // output '2020/08/09T01:02:03'

Conclusion

We just did the conversion of ordinary strings here, and there are some shortcomings

  1. There is no built-in date check
  2. Date format similar to 01/10/07 is not taken into consideration

Interested friends can play and enrich our conversion methods.

Reference

Comments