You ask whether or not it's "safe" to do that, but what you actually mean is if it's "effective" to do that. The answer is no.
In fact, there is no possible way for you to implement a software that the client uses, but only for a limited time. This approach is called DRM, or Digital Rights Management, and has failed every single time it was tried. Let's have a look through some approaches:
Approach 1: The client checks the time locally.
Say, the license is nothing but a UNIX timestamp and the client simply verifies whether or not this timestamp has already passed.
The attacker has several possible ways to circumvent your DRM:
- Change their system clock
- Change the function to always return a low UNIX timestamp
- Change the license to be a date far in the future
- Change the function that completes the check to always
return true;
- Completely remove the check
As you see, there are plenty of ways to circumvent this, and those were just the ones I could think of right now.
Approach 2: The client asks for the time remotely.
Instead of asking the client what time it is, the client could ask a trusted server, possibly under your control, what the time is. You might think that that fixes at least some of our attack vectors, right? It does, but it introduces a new one: We can simply forge the reply from the server and make the client believe it's actually from the past.
Approach 3: Cryptography!
If in doubt, throw crypto at it and see what sticks, right? You could make all requests and responses signed, but what stops a malicious client from just signing a fake timestamp with their own key? The client must have the public key stored somewhere, and so the malicious user can replace it with a public key of their choice.
You might think a symmetric cipher would be better, since you could just keep the key secret - but it doesn't work like that. The client needs to have the secret key too.
Approach 4: Obfuscation!
This one is an approach that is used a lot. Just do many many different things that make no sense, make your logic as twisted as possible, sown all around the codebase, and just in general give every attacker a headache when they try to reverse it.
That sounds cool, until you realize that this also makes debugging in-the-field errors a nightmare, and that it doesn't really keep the attacker out, it just delays them. And once they found a way, they can just create a program that does the necessary steps for them.
Approach 5: Give up!
This is by far the easiest approach. Dedicated malicious users will find a way to "crack" your program. And honest users will buy a license anyways. So just don't worry about it.