Multiple reasons. First, the DateTime type in a typical database isn't even an RFC-3339 string; its a unix timestamp. That's it; an unsigned integer. This is very space efficient; far more-so than a string. So, then, why the indirection; why not just use the integer type directly? It communicates to the database engine the intent of the data stored, so the database can do useful things like, for example, time-based queries, interfacing with that integer in more human friendly ways when writing queries, displaying it in a more friendly way... its a low-cost abstraction, generally.
Except, there is the cost intrinsic to this discussion, where going back to strings makes sense. That doesn't mean that decision comes with no cost. If you store someone's birthday as "1990-02-05", then need to answer the question "who has birthdays in the next month", that's actually essentially impossible to do in practically any database query engine. You have the problem of both ignoring the year field of that string (ok, so, maybe we just store "02-05" because the year doesn't matter for birthdays, moreso just 'dates of birth', we can denormalize)... but even beyond that, the closest most if not all engines could get is generating an array of every upcoming day in application code (02-05, 02-06, 02-07, etc) then matching on each. Alternatively, just sort on the field (sans year) then filter in application code, but that's also not happening in the database, which has negatives, and moreover, this would suddenly start failing across year boundaries, but you can special-case that by running a second query starting at 01-01 if the first one didn't return enough results...
There's no easy solution. Time is just really hard. Its good to have as many tools as possible in your belt, but with that you have to know when to reach for one versus another. There isn't one solution to any of these problems.