Encontrei a solução. 
	 
	Fiz uma query utilizando a função generate_series() para gerar datas entre os períodos para cada um dos cargos listados.
 
	Ordenei e fiz um case para determinar que quando houvessem datas iguais para os dois tipos de cargo, que trouxesse somente o do cargo predominante, que seria VP quando não houvesse, traz o cargo de DI.
 
	Com isso consegui montar a linha do tempo detalhada, data a data.
 
	Para resumir isso da forma que estava somente com data início e data fim, tive que utilizar função e armazenar os dados em variáveis para fazer inserts e updates no banco.
 
	Segue o script que fiz, creio que ainda caiba melhorias:
 
--CRIANDO OU REGRIANDO A FUNÇÃO
CREATE OR REPLACE FUNCTION f_gera_linha_tempo(
	--LOCAL PARA DECLARAR PASSAGEM DE PARÂMETROS
 	)
     RETURNS bigint
     LANGUAGE 'plpgsql'
     COST 100
     VOLATILE PARALLEL UNSAFE
 AS $BODY$
  DECLARE
 	--DECLARANDO AS VARIÁVEIS
  	VFuncao		CHARACTER VARYING(100);
	VFuncaoAux	CHARACTER VARYING(100);
   	VNuFuncao			INTEGER;
	VNuFuncaoAux		INTEGER;
	i				INTEGER;
   	rec_linha		RECORD;
 	
  BEGIN
  --INICIALIZANDO AS VARIÁVEIS
  VFuncao = '';
  VFuncaoAux = '';
  VNuFuncao = 0;
  VNuFuncaoAux = 0;
  i = 0;
--DELETA OS DADOS DA TABELA PARA RECRIAR COM A FUNÇÃO
DELETE FROM tb_linha_tempo;
--INICIA LOOP
FOR rec_linha IN
--CONSULTA QUE CARREGA OS REGISTROS DO LOOP
/*	A CONSULTA IRÁ EXPANDIR OS PERÍODOS DIA A DIA USANDO GENERATE_SERIES PARA PODER ISOLAR OS 
	DIAS QUE SERÃO DESCONSIDERADOS NA SOBREPOSIÇÃO, MANTENDO SOMENTE OS DIAS QUE DEVERÃO SER CONSIDERADOS
	NA MONTAGEM DA LINHA DO TEMPO 
	
CADASTRO: (o que eu tenho)
DI1 = 01/01/2023 A 31/03/2023
VP1 = 10/01/2023 A 20/01/2023
VP2 = 10/02/2023 A 20/03/2023
DI2 = 01/04/2023 A 10/04/2023
*/
WITH funcoes AS (
SELECT	ROW_NUMBER() OVER (ORDER BY r.datas) AS sequencia,
		r.no_funcao,
		r.datas
FROM (
SELECT
	DISTINCT 
	a.no_funcao,
	CASE WHEN SUBSTRING(a.no_funcao,1,2) = 'DI' THEN 1 ELSE 2 END AS cod_funcao, 
 	generate_series(
	a.dt_inicio::DATE,
 	DATE(a.dt_fim - INTERVAL '1 DAY')::DATE,
	'1 day')::DATE AS datas
FROM	tb_funcoes AS a
) AS r
ORDER	BY datas
),
menor_funcao AS (
SELECT no_funcao, datas, MIN(cod_funcao) AS cod_funcao FROM funcoes GROUP BY 1,2
)
SELECT	dir.no_funcao,
		dir.datas
FROM	funcoes AS dir
		INNER JOIN menor_funcao AS mo ON mo.cod_funcao = dir.cod_funcao AND mo.no_funcao = dir.no_funcao AND mo.datas = dir.datas
ORDER	BY dir.datas
--COMEÇA A EXECUTAR O LOOP
 LOOP
--VARIÁVEIS PRINCIPAIS RECEBEM OS VALORES
VFuncao = rec_linha.no_funcao;
VNuFuncao = rec_linha.cod_funcao;
--SE AS VARIÁVEIS PRINCIPAIS FOREM DIFERENTES DAS AUXILIARES, ENTRA NA CONDIÇÃO
IF (VFuncao != VFuncaoAux AND VNuFuncao != VNuFuncaoAux) THEN
i = i + 1; --VARIÁVEL QUE SERVIRÁ DE ID NA TABELA
--VARIÁVEIS AUXILIARES RECEBEM O MESMO VALOR DA VARIÁVEL PRINCIPAL
VFuncaoAux = rec_linha.no_funcao;
VNuFuncaoAux = rec_linha.cod_funcao;
--INSERE LINHA NA TABELA COM DATA FIM AINDA NULA
INSERT INTO tb_linha_tempo(id_linha, no_funcao, dt_inicio,dt_fim, cod_funcao)
	VALUES (i, rec_linha.no_funcao, rec_linha.datas, null, rec_linha.cod_funcao);
ELSE
		--SE OCORRÊNCIA PRINCIPAL DIFERENTE DA AUXILIAR, ENTRA NA CONDIÇÃO
		IF (VNuFuncao != VNuFuncaoAux) THEN
		--VARIÁVEL AUXILIAR RECEBE O VALOR DA OCORRÊNCIA
		VNuFuncaoAux = rec_linha.cod_funcao;
		i = i + 1; --INCREMENTA O ID
		--INSERE LINHA NA TABELA
		INSERT INTO tb_linha_tempo(id_linha, no_funcao, cod_funcao)
			VALUES (i, rec_linha.no_funcao, rec_linha.datas, null, rec_linha.cod_funcao);
		
		ELSE
		--FICA ATUALIZANDO A DATA FIM ATÉ QUE O LOOP MUDE DE OCORRÊNCIA, A ÚLTIMA DATA A SER ATULIZADA É A QUE FECHA O PERÍODO
		UPDATE tb_linha_tempo
		SET dt_fim = rec_linha.datas
		WHERE id_linha = i;
		
		END IF; --segundo SE
END IF; --primeiro SE
END LOOP;
		--ATUALIZA A DATA FIM DAS LINHAS COM DT_FIM NULA
		--A DT_FIM FICA NULA QUANDO SÓ EXISTE UM REGISTRO DE DATA PARA A OCORRÊNCIA DO EMPREGADO
		UPDATE tb_linha_tempo
		SET dt_fim = dt_inicio
		WHERE dt_fim IS NULL;
  	RETURN 0;
  END;
 
 $BODY$;
 ALTER FUNCTION f_gera_linha_tempo()
     OWNER TO postgres;
-- SELECT f_gera_linha_tempo()
-- DROP FUNCTION f_gera_linha_tempo()
-- SELECT * FROM tb_linha_tempo ORDER BY 1
-- DELETE FROM tb_linha_tempo