optimizing or estimating postgresql table size on disk
The best way is to run a little benchmark:

INSERT INTO tb_user
   (user_firstname, user_familyname, user_email, user_gender, user_crtime)
SELECT substr(md5(random()::text), 1, 15),
       substr(md5(random()::text), 1, 15),
       md5(random()::text),
       'F',
       current_date
FROM generate_series(1, 1000000);

SELECT pg_size_pretty(pg_total_relation_size('tb_user'));

 pg_size_pretty 
----------------
 126 MB
(1 row)


A text or varchar that is short enough (which the ones in the table certainly are) will consume one byte more than the number of bytes in the string.

There is some overhead caused by block and tuples headers and other metadata, as well as by fragmentation (some empty space will remain in each 8kB block). And then the index that supports the primary key is also sizeable:

\di+ tb_user_pkey 
                            List of relations
 Schema  |     Name     | Type  |  Owner  |  Table  | Size  | Description 
---------+--------------+-------+---------+---------+-------+-------------
 laurenz | tb_user_pkey | index | laurenz | tb_user | 21 MB | 
(1 row)


Some additional hints:


You can save a little space by having user_crtime in the second position. Otherwise, you might lose up to three bytes to padding.
Use bigint for the primary key so that you can never run out of values. Trying to save on these 4 bytes is usually not a good idea.