The openssl command is installed on almost every Linux server and on macOS. To read the certificate a live website serves:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate
The output is a single line such as notAfter=Jan 14 23:59:59 2027 GMT. Use -dates instead of -enddate to see the start date as well. The -servername option matters: servers that host several sites use it to choose which certificate to send.
To check a certificate file on the server itself, for example one issued by Certbot:
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -enddate
To ask whether a certificate expires within the next 30 days (2,592,000 seconds), which is handy in scripts:
openssl x509 -in cert.pem -noout -checkend 2592000
It prints "Certificate will expire" or "Certificate will not expire", and the exit code is 1 when it will expire.
To print the days left for a live site on Linux:
end=$(echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
echo $(( ($(date -d "$end" +%s) - $(date +%s)) / 86400 )) days left
On a Mac, date works differently, so use the first command and read the date.
If you use Certbot, sudo certbot certificates lists every certificate it manages with its expiry date and the number of days it remains valid.