The first command actually writes a single block (count = 1) of size 1 Mb and skip 30000 blocks of the same size, that is 30 Gb. In practice it allocates 30.001 Gb on the filesystem, but the actual disk space used is only 1 Mb. The result is a sparse file
The second command creates an empty file, as stated in the man page of truncate:
Shrink or extend the size of each FILE to the specified size
A FILE argument that does not exist is created.
If a FILE is larger than the specified size, the extra data is lost. If a FILE is shorter, it is extended and the extended part (hole) reads as zero bytes.
In this case the original size was 0 bytes (since it was a non existent file) and being shorter than 30 Gb the extended part is 0 bytes long. The difference is between the ls and du commands: the former reads the information in the inode, therefore it reports the allocated space; the latter reports the actual physical space used. If you use the option --apparent-size of the du command, you should see 30 Gb as reported by ls.