I don't even try for 100% statement coverage. I use coverage to help identify important missing test cases.
For example, some of my code will read/write a binary format of my own devising. The format is used in a "friendly" environment, so I don't have to worry about malicious users trying to cause failures. (The code is in Python, which eliminates a lot of the memory error that a malicious user could use.)
I could get 100% coverage by creating corrupted binary files in all of the different ways to fail. But why go through the work of testing unrealistic cases?
Instead, I use my experience and intuition to only test the realistic cases. I also know that my code is not mission critical, so if one of my users reports a failure, I'll send them a patch or point release.
I can't give you a breakdown of time because I don't track it. My usual estimate is 1/3 programming, 1/3 testing, and 1/3 documentation, for commercial-quality packages. I find that writing good documentation helps find bugs that users are likely to experience.
(Now that I think of it, that binary format took several months to write. The first two attempts didn't scale and I had to toss them. They had almost no tests, so think of them as spikes.)
For consulting, it depends on the project. In one two-week project I had no tests. The control flow was simple and most of the code was executed during normal use. Plus, the support staff was able to maintain the software in case of errors, and we did a thorough code review for knowledge transfer.
In another project, I was brought in to optimize some existing code, which didn't have tests but which had been extensively tested manually. It was presumed to be correct. The new code I wrote also didn't have unit tests. Instead, I cross-compared a few million inputs to check that they gave the same results, at about 10x performance.
In yet another project, I had unit tests for the user-facing parts, but not for the main algorithm. Rather than explain the program, I'll use an analogy. Consider a program to factor a number into its primes. This is difficult. On the other hand, it's easy to test that the result is correct. Multiply the numbers to see if they give the original number, and use a primality test to ensure all of the factors are prime.
In essence, I have a #define which enables verification. This also slows things down, so it's not enabled by default. I then (once again) processed a few million inputs. This sort of integration testing is much more complete than manual unit tests.
(I do have a simple unit test used as a burn test, so it's not completely untested.)
For an extreme case, see https://randomascii.wordpress.com/2014/01/27/theres-only-fou... . Why write unit tests when it's possible to examine all 2^32 possibilities in 90 seconds?