DEV Community

Audiophile
Audiophile

Posted on

Two string methods every JavaScript developer should know.

The Challenge:

I was working on a project recently where I was required to build an endpoint that enabled the client to be able to query the Mongo database based on a single date, and also a date range. I know, exciting!

Here's the thing though, while testing the endpoint, I realized that I wasn't successfully querying the db because I was getting the date in this form '"2019-08-02T00:00:00.000Z"'. Meanwhile I needed it in this form: '2019-08-02'. So I needed to separate the time from the date-time string and remove the double quotes from the string.

In case you're interested, I wrote about how to query NoSQL databases with date-ranges here:

What I tried:

I did what every respectable developer does when they hit roadblocks: I scoured the realms of Stack Overflow looking for a RegEx to solve the issue!

While searching, I saw lots of answers that worked but didn't make any sense to me, and I wasn't quite comfortable with adding that to the code base. Fixing code that works but you don't understand is a practice I'd rather not get used to.

I came across an answer that used the JavaScript string's split() method. I became curious and searched for the String object on Google, just to see what came up. I won't bother you with too much talk on all the different methods I found. I'll only bother you with the two that solved my challenge.

String.prototype.split() in action!

A quick search on M.D.N describes the split() method as such:
The split() method turns a String into an array of strings, by separating the string at each instance of a specified separator string.

You may be thinking "Uh-huh, in English please...", no worries, I thought the same. So here's an alternative definition:

The split method helps you cut down a desired Mama String into smaller child strings and it performs this separation based on the condition you give it. It then returns the answer back to you as an Array

This condition is called a separator. A very important thing to note about the separator is that it must exist in the string. So if you instruct the split method and say:
"Hey I want you to cut down a Mama String called data into smaller child strings using a comma."

Split says ok and jumps to action!


let data = "data";

data = data.split(',');

console.log(data);

//Expected Result: ["data"];

You may be thinking, "hold up, Mr. split, don't think you can fool me by fixing the string I passed to you by putting it into an array". Don't be too hasty there, here's what happened; we told split() to give us child strings from the Mama string we passed to it using a separator that wasn't part of the Mama string. So the Mama string looks at itself and is like "I don't have any commas, so I can't be separated by it".

However, what if we tweaked our separator to a similar value, say the letter "a". Let's see:


let data = "data";

data = data.split('a');

console.log(data);

//Expected Result: ["d", "t", ""];   

Aha! We get little child strings wherever the letter a was found. So Mr. split() takes the separator and uses it as a mini-search criteria where the Mama string is cut down wherever the separator shows. Then it skips the separator and returns anything after it also, hence the "" we get as part of our result above.

But what if we wanted the separation in just a number of places?

That's okay too, split() makes that convenient for you by providing an optional limit parameter you can fix into it. The catch though, is that once the limit is reached, split stops trying to separate the Mama string and gives you only what has been separated so far. So assuming we wanted our "data" string to be split by the letter "a" just once and no more, we would get something like this:


let data = "data";

data = data.split('a', 1);

console.log(data);

//Expected Result: ["d"];   

Okay but how does this fix my Date-Time problem?
If you recall, I had a date-time string that looked like this: '"2019-08-02T00:00:00.000Z"'. With the brand new knowledge I gained, I could then do away with the timestamp part of the date-time I got. So I would have something like this:


   let date = '"2019-08-02T00:00:00.000Z"';

    date = date.split('T', 1);

   console.log(date);

   //Expected result: ['"2019-08-02"]

Now I have my date! But how about the double-quotes issue though? How do I solve that?

String.prototype.replace() to the rescue!

Here's what replace() does, it takes in the string you want gone as the first parameter, and the string you want to introduce as the second parameter. So it goes like this:

string.replace(/stringIHate/,'StringILove')

It uses double forward-slashes to house the string you want gone. This also allows you to add things like the letters i to instruct that you want the search to be case-insensitive or g to instruct that you want the search to be global i.e. everywhere it is found in the string.

So to resolve our issue, we'd use it as such:


   let date = '"2019-08-02T00:00:00.000Z"';

    date = date.split('T', 1);

   console.log(date);

   //Expected result: ['"2019-08-02"]

  //REPLACE METHOD
   date = date[0].replace(/"/,"");

   console.log(date);

   //Expected result: "2019-08-02"

Voila! I finally have my date in the form I want it. I did so by telling Mr. replace() to search through my string in the returned array, look for double quotes and replace them with nothing.

Chaining replace() and split(): A better way.

In order to boost efficiency, we could shorten the lines of code we need to write by chaining string methods together. Also, it would be better to call the replace function on the string first before calling the split function because it makes our code shorter. Hence we could condense the code as such:

   let date = '"2019-08-02T00:00:00.000Z"';

   date = date.replace(/"/g, "").split('T',1);

  console.log(date);

 // Expected Result: ["2019-08-02"];

//This is shorter and more semantic than:
date = date.split('T',1)[0].replace(/"/g, "");

//You could do that however if you don't want the string to be returned as an array

Conclusion

I hope you found that helpful. Before you reach out for a Regular Expression you-don't-quite-understand-but-works to solve your string-related issues, try to take a deeper look at JavaScript string methods. Please like, share and leave comments so more people who need this can see it!

What other String methods have helped make life easy for you?

Top comments (35)

Collapse
 
arielrodriguez profile image
Ariel Rodriguez

So far is fine to play a bit with strings. But I'd like to share from my experience, always try to manipulate the objects with their respective API. In this case you are facing a formatted string RFC-3339, and you want to extract its = date-fullyear "-" date-month "-" date-mday

I highly recommend to avoid regex. You should implement Date API, you can achieve easily with 2 lines of code and solid code scalable. As many other answered to you, try to play with Date, as example:

const date = new Date("2019-08-02T00:00:00.000Z")

const fullDate = ${date.getFullYear()}-${date.getMonth()}-${date.getDay()}

Note: toLocaleString is experimental and not stable yet.

You may normalize getMonth and getDay to add 0 to the left when needed.

Collapse
 
_hoyet profile image
Jeremiah Hoyet

They would have still needed to use string.replace to remove the double quotes around the date string, but I prefer your approach of using the Date APIs to ensure you're always going to get the same result.

Collapse
 
p12y profile image
Peter Tyldesley

Not necessarily, you could do it with String.slice or JSON.parse instead.

Collapse
 
losd profile image
Dennis Du Krøger

"Note: toLocaleString is experimental and not stable yet."

For Date (and most other built-in objects)? No it isn't.

developer.mozilla.org/en-US/docs/W...

Collapse
 
fidelve profile image
FidelVe

Great post!.

Whenever I'm in a position where I can implement different solutions to the same problem involving strings, I try to follow this decision tree:

desicion tree

I always try to write solutions with as few lines as possible without compromising readability.

For your task, this also works:

> let date = '"2019-08-02T00:00:00.000Z"'
> date.substring(date.indexOf('"') + 1, date.indexOf("T"))
'2019-08-02'
Collapse
 
rubyrubenstahl profile image
Ruby Rubenstahl

If it's a fixed format you can just slice it out without having to spend CPU cycles searching.

const dt = '"2019-08-02T00:00:00.000Z"';
const date = dt.slice(1,11);
console.log(date);

The methods in the article are definitely handy to have in your toolkit though.

Collapse
 
brandito profile image
brandito • Edited

.slice(), .substr() and .substring() can all achieve this but I agree completely that it should be done with the fixed indexes since its quite apparent the data is all in the same format given his example and glad that my first thought was apparently the most efficient!

edit: turns out substr is non-standard and substring should be used instead

Collapse
 
itz_giddy profile image
Audiophile

Wow this is brilliant, didn't know you could do that in just one line of code. Thanks for sharing Fidel, I appreciate it!

Collapse
 
madeinmilwaukee profile image
Chuck Watson

Since you know the exact input maybe less is more here?
let date = '"2019-08-02T00:00:00.000Z"';
date = date.substr(1, 10);

Collapse
 
drinkcsis profile image
drinkcsis • Edited

Interesting...
But how about this?

new Date("2019-08-02T00:00:00.000Z").toLocaleDateString("sq-AL",{ year: 'numeric', month: '2-digit', day: '2-digit' })

Collapse
 
pulges profile image
Oliver Pulges

This method will only work if your javascript environment (browser or server in case of nodejs) is guaranteed to run in UTC. In case of other timezones or daylight saving time shift you can get an error of +-1 days as Date object parses this to local environment time.

Collapse
 
drinkcsis profile image
drinkcsis • Edited

Actually... No.
Date doesn't parse this to local environment time.
That string contains T00:00:00.000Z.It is timezone of date(UTC in current case) . So it will convert correct in every environment!

Thread Thread
 
pulges profile image
Oliver Pulges

Exactly what I was saying, that this is only valid when that timezone containing string is generated in the same environment. I'm living in UTC+2 and parsing the string withe Zulu Z time in the end (set time to 23h to make the point):

new Date("2019-08-02T23:00:00.000Z").toLocaleDateString("sq-AL",{ year: 'numeric', month: '2-digit', day: '2-digit' });

returns 08/03/2019

Thread Thread
 
drinkcsis profile image
drinkcsis

That is way it is good practis to set all servers in utc

Thread Thread
 
pulges profile image
Oliver Pulges • Edited

But you can not guarantee users with their computers to stay put in UTC too. Nobody told the string was parsed in server. If it was though then the split method just calls for SQL injection attack.

Thread Thread
 
danstur profile image
danstur

Also no sane person ever thought "put all your servers in the wrong timezone" was a good idea.

Instead of trying to work around bugs in your code by making every single recorded time in your server wrong, just learn the involved concepts and the available APIs.

Collapse
 
dmratcliffe profile image
Devin Ratcliffe • Edited

This is the answer.

Also, it's strange, because I feel most people know about these string operations.

This is not the situation to use them though, it's mildly ridiculous this was the accepted answer...

To be more clear, the date function can parse more formats of dates then this fix, will the date always have a T? Also the format is decidedly js, which means it probably came from the date function already.

Collapse
 
jalovatt profile image
Adam Lovatt

So you thought of using a RegEx, ended up discovering Split, then had to use a RegEx in your Replace anyway?

At that point you might as well go all-in:

const justDate = date.match(/"(.+)T/)[1]

(Typed on a phone, may not be perfect)

Collapse
 
itz_giddy profile image
Audiophile

Hi Adam, so I guess the point for me was applying something that I understood. My knowledge of RegEx isn't the best, and I wanted to apply something in the code base I could explain if asked. Thanks for sharing!

Collapse
 
jalovatt profile image
Adam Lovatt • Edited

That's fair, though I would argue the level of RegExiness involved here is something everyone should make a point of learning because it solves so many problems.

An even shorter alternative, since you know the input format won't change: const justDate = date.slice(1, 11).

Collapse
 
euler2718 profile image
John Corley

Yea I was thinking the exact same thing. Probably didn't notice the /"/g was regex

Collapse
 
devnamedjosh profile image
Josh Patton

Well written and easy to follow article.

I know your solution works, but manipulating an ISO datetime string directly makes me uncomfortable. I'd rather put it in a Date object or outside library and then format it in the desired way.

But I over-engineer things and your solution is simpler and has a lower cognitive load. Still learning this lesson.

Thanks for reminding me to keep it simple!

Collapse
 
danstur profile image
danstur • Edited

What happened here is that you got a datetime object formatted as json. So yes you could manually parse the json (it is pretty trivial after all), but there's a built-in solution to handle this: JSON.parse().

After you've done that you'll have to deal with the fact that JavaScript's datetime library is about as bad as possible. So instead of dealing with the catastrophe that the built-in API is, simply use moment.js. Which combined results in the rather pleasant moment(JSON.parse(inputStr)).format('YYYY-MM-DD')

(You should obviously do error handling along the way).

Collapse
 
lnshimmell profile image
LNShimmell

date.substr(1,11);

Collapse
 
dirtycode1337 profile image
Dirty-Co.de

That would include the Z in the string ;)

Collapse
 
brandito profile image
brandito

Haha turns out substr would get the T not the Z and substring would get the correct string with the same args

Thread Thread
 
lnshimmell profile image
LNShimmell

Both of you are wrong but okay... it would not get either.

date= '"2019-08-02T00:00:00.000Z"';
console.log(date.substr(1,11);

go ahead and run in your console. I'll wait.

Thread Thread
 
brandito profile image
brandito
Collapse
 
johkycheng profile image
Johky • Edited

If I have to do this, I will use only regex replace instead of using both split and regex, where regex only already can achieve this :

var str = '"2019-08-02T00:00:00.000Z"';

var res = str.replace(/.*(\d{4}\-\d{2}\-\d{2}).*/, "$1");

This way also will not care about other string inside the string, it will just try to find 9999-99-99 and remove others.
It will accept any format with this pattern.

Eg. :
2019-08-02 00:00:00
Friday, 2019-08-02 00:00:00

Collapse
 
jkirchartz profile image
Dr Rev J Kirchartz

As the old joke goes "I decided to use regex and now I have 2 problems"... regex is a very useful tool but doesn't need to be your only tool, and as usual with programming it's easy to overcomplicate things.

Collapse
 
neophytewriter profile image
Michael Shea

Great explanations that even a noob like me can understand! Thank you! I'll be looking for more articles from you in the future.

Collapse
 
itz_giddy profile image
Audiophile

I'm glad it helped!

Collapse
 
thechazhall profile image
C.F. Hall

Very cool. Thanks Sir!

Collapse
 
davehoran profile image
Dave Horan

Nicely done. You can certainly use regex in the future, but this time around you discovered the magic of split and replace for string manipulation. More tools in your code toolbox.

Collapse
 
juanmendes profile image
juanmendes

Why would you parse the date manually and then format it manually? Use Date.parse and toLocaleString stackoverflow.com/a/34015511/227299

-1