Where to put single quotes? I am trying to execute the below statement which creates a database called service2019:

DECLARE @dbname VARCHAR(50);
SET @dbname = 'service' + CAST(YEAR(GETDATE()) AS VARCHAR(4));


EXEC (
'CREATE DATABASE ' + @dbname  + ' ON  PRIMARY 
( NAME =' + '' + @dbname +'' + ', FILENAME = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\''' + '''' + @dbname + '''' + '''.mdf'''  + ', SIZE = 10MB , MAXSIZE = UNLIMITED, FILEGROWTH = 100KB )
 LOG ON 
( NAME =' + '' + @dbname + '_log' + ', FILENAME = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\''' + '''' + @dbname + ''''+'''.ldf''' + ', SIZE = 10MB , MAXSIZE = 2048GB , FILEGROWTH = 100KB )'
)


I get the correct database name and logical names. The problem is I get wrong physical names:

'service2019'.mdf

'service2019'.ldf

Could someone explain to me how these quotes actually work? There are some parts where it is clear but sometimes it becomes a challenge to figure out where to put those quotes.
When developing Dynamic SQL, I suggest you start your efforts by making heavy use of the PRINT command rather than EXEC as things can (and often do) go wrong with Dynamic SQL.  Printing out your statement instead of actually running it will help you avoid some issues if you end up having syntactically correct code that is logically wrong.

In this specific case, I'm adding a new parameter, @DSQL VARCHAR(MAX), setting that variable with the command, and printing it out, as follows:

DECLARE @dbname VARCHAR(50), @DSQL VARCHAR(MAX);
SET @dbname = 'service' + CAST(YEAR(GETDATE()) AS VARCHAR(4));


SET @DSQL = 'CREATE DATABASE ' + @dbname  + ' ON  PRIMARY 
( NAME =' + '' + @dbname +'' + ', FILENAME = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\''' + '''' + @dbname + '''' + '''.mdf'''  + ', SIZE = 10MB , MAXSIZE = UNLIMITED, FILEGROWTH = 100KB )
 LOG ON 
( NAME =' + '' + @dbname + '_log' + ', FILENAME = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\''' + '''' + @dbname + ''''+'''.ldf''' + ', SIZE = 10MB , MAXSIZE = 2048GB , FILEGROWTH = 100KB )'


PRINT @DSQL


Which outputs the following:

CREATE DATABASE service2019 ON  PRIMARY 
( NAME =service2019, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\''service2019''.mdf', SIZE = 10MB , MAXSIZE = UNLIMITED, FILEGROWTH = 100KB )
 LOG ON 
( NAME =service2019_log, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\''service2019''.ldf', SIZE = 10MB , MAXSIZE = 2048GB , FILEGROWTH = 100KB )


As you can see, you have too many quotes around service2019 in your mdf and ldf filepaths.  Upon further investigation, it also looks like you have more string concatenations than necessary.  What I suggest you do is limit concatenations (i.e. +) to only the times where you transition between variables and static strings.  I'm also a fan of formatting my DSQL, so I'm also including a Carriage Return/Line Feed (i.e. \r\n) and Tab (i.e. \t) variables so your output looks a little cleaner.  Removing the unnecessary concatenations, including the formatting, and cleaning up the quotes gets me the following: 

DECLARE @dbname VARCHAR(50), @DSQL VARCHAR(MAX), @CRLF CHAR(2), @TAB CHAR(1);
SET @dbname = 'service' + CAST(YEAR(GETDATE()) AS VARCHAR(4));
SET @CRLF = CHAR(13) + CHAR(10)
SET @TAB = CHAR(9)


SET @DSQL = 'CREATE DATABASE ' + @dbname  + ' ON  PRIMARY 
( NAME = ' + @dbname + ', FILENAME = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\' + @dbname + '.mdf'' , SIZE = 10MB , MAXSIZE = UNLIMITED, FILEGROWTH = 100KB )' 
+ @CRLF + @TAB + 'LOG ON' 
+ @CRLF + '( NAME = ' + @dbname + '_log' + ', FILENAME = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQL2014TEST\MSSQL\DATA\' + @dbname + '.ldf'' , SIZE = 10MB , MAXSIZE = 2048GB , FILEGROWTH = 100KB )'


PRINT @DSQL
--EXEC(@DSQL)   /* &lt;--- Uncomment out if you want to run this */


For more formatting suggestions, discussions of pitfalls that come with DSQL, and pretty much anything else, I'll point you to (what I consider the defacto guide on DSQL) The Curse and Blessings of Dynamic SQL by Erland Sommarskog.