core: fix timezone

Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
rodrigo committed 2026-03-29 17:10:28 -03:00
1 parent 5193b2df08
commit c42202b727
3 files changed
+81 -22

No files matched your search

+77 -22
View File
@@ -111,10 +111,13 @@ class DateProcessor {
if (this.diasSemana.hasOwnProperty(diaNome)) {
const diaSemanaTarget = this.diasSemana[diaNome];
const data = this.obterProximoDiaSemana(diaSemanaTarget);
data.setHours(hora, minuto, 0, 0);
const proxData = this.obterProximoDiaSemana(diaSemanaTarget);
if (this.isValidTime(hora, minuto)) {
// Obter componentes da data no fuso Brasil
const partes = this.extrairPartesBrasil(proxData);
const data = this.criarDataBrasil(partes.ano, partes.mes, partes.dia, hora, minuto);
return {
success: true,
data,
@@ -153,11 +156,15 @@ class DateProcessor {
if (this.palavrasTemporais.hasOwnProperty(palavraTemporal)) {
const diasOffset = this.palavrasTemporais[palavraTemporal];
const data = new Date();
data.setDate(data.getDate() + diasOffset);
data.setHours(hora, minuto, 0, 0);
if (this.isValidTime(hora, minuto)) {
// Basear no dia atual no fuso Brasil e aplicar offset
const hoje = this.extrairPartesBrasil(new Date());
const base = this.criarDataBrasil(hoje.ano, hoje.mes, hoje.dia, 12, 0);
base.setDate(base.getDate() + diasOffset);
const partes = this.extrairPartesBrasil(base);
const data = this.criarDataBrasil(partes.ano, partes.mes, partes.dia, hora, minuto);
return {
success: true,
data,
@@ -213,7 +220,7 @@ class DateProcessor {
if (ano < 100) ano += 2000; // Converter anos de 2 dígitos
if (mes !== undefined && this.isValidDate(dia, mes, ano) && this.isValidTime(hora, minuto)) {
const data = new Date(ano, mes, dia, hora, minuto, 0, 0);
const data = this.criarDataBrasil(ano, mes, dia, hora, minuto);
return {
success: true,
@@ -251,34 +258,55 @@ class DateProcessor {
const quantidade = parseInt(match[1]);
const unidade = match[2].toLowerCase();
const data = new Date();
let data = new Date();
if (unidade.includes('dia')) {
data.setDate(data.getDate() + quantidade);
const base = this.extrairPartesBrasil(new Date());
const tmpDate = this.criarDataBrasil(base.ano, base.mes, base.dia, 12, 0);
tmpDate.setDate(tmpDate.getDate() + quantidade);
if (match[3] && match[4] !== undefined) {
const hora = parseInt(match[3]);
const minuto = match[4] ? parseInt(match[4]) : 0;
if (this.isValidTime(hora, minuto)) {
data.setHours(hora, minuto, 0, 0);
const partes = this.extrairPartesBrasil(tmpDate);
data = this.criarDataBrasil(partes.ano, partes.mes, partes.dia, hora, minuto);
} else {
data = tmpDate;
}
} else {
data = tmpDate;
}
} else if (unidade.includes('semana')) {
data.setDate(data.getDate() + (quantidade * 7));
const base = this.extrairPartesBrasil(new Date());
const tmpDate = this.criarDataBrasil(base.ano, base.mes, base.dia, 12, 0);
tmpDate.setDate(tmpDate.getDate() + (quantidade * 7));
if (match[3] && match[4] !== undefined) {
const hora = parseInt(match[3]);
const minuto = match[4] ? parseInt(match[4]) : 0;
if (this.isValidTime(hora, minuto)) {
data.setHours(hora, minuto, 0, 0);
const partes = this.extrairPartesBrasil(tmpDate);
data = this.criarDataBrasil(partes.ano, partes.mes, partes.dia, hora, minuto);
} else {
data = tmpDate;
}
} else {
data = tmpDate;
}
} else if (unidade.includes('mes')) {
data.setMonth(data.getMonth() + quantidade);
const base = this.extrairPartesBrasil(new Date());
const tmpDate = this.criarDataBrasil(base.ano, base.mes, base.dia, 12, 0);
tmpDate.setMonth(tmpDate.getMonth() + quantidade);
if (match[3] && match[4] !== undefined) {
const hora = parseInt(match[3]);
const minuto = match[4] ? parseInt(match[4]) : 0;
if (this.isValidTime(hora, minuto)) {
data.setHours(hora, minuto, 0, 0);
const partes = this.extrairPartesBrasil(tmpDate);
data = this.criarDataBrasil(partes.ano, partes.mes, partes.dia, hora, minuto);
} else {
data = tmpDate;
}
} else {
data = tmpDate;
}
} else if (unidade.includes('hora')) {
data.setHours(data.getHours() + quantidade);
@@ -340,6 +368,31 @@ class DateProcessor {
return hora >= 0 && hora <= 23 && minuto >= 0 && minuto <= 59;
}
/**
* Criar um Date com hora no fuso America/Araguaina,
* independente do TZ do servidor.
*/
criarDataBrasil(ano, mes, dia, hora, minuto) {
// Constrói uma string ISO no fuso -03:00 para garantir
// que a hora digitada pelo usuário seja tratada como BR.
const pad = (n) => String(n).padStart(2, '0');
const isoStr = `${ano}-${pad(mes + 1)}-${pad(dia)}T${pad(hora)}:${pad(minuto)}:00-03:00`;
return new Date(isoStr);
}
/**
* Extrair {ano, mes(0-11), dia} de um Date no fuso Brasil.
*/
extrairPartesBrasil(data) {
const fmt = new Intl.DateTimeFormat('en-CA', {
timeZone: 'America/Araguaina',
year: 'numeric', month: '2-digit', day: '2-digit'
});
// en-CA produz YYYY-MM-DD
const [ano, mes, dia] = fmt.format(data).split('-').map(Number);
return { ano, mes: mes - 1, dia };
}
/**
* Formatar data para string legível
*/
@@ -352,7 +405,7 @@ class DateProcessor {
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZone: 'America/Sao_Paulo'
timeZone: 'America/Araguaina'
};
return data.toLocaleDateString('pt-BR', opcoes);
@@ -360,18 +413,20 @@ class DateProcessor {
/**
* Formatar data para o formato do sistema (YYYY-MM-DD HH:mm:ss)
* Retorna sempre no horário de Brasília.
*/
formatarParaSistema(data) {
if (!(data instanceof Date)) return null;
const ano = data.getFullYear();
const mes = String(data.getMonth() + 1).padStart(2, '0');
const dia = String(data.getDate()).padStart(2, '0');
const hora = String(data.getHours()).padStart(2, '0');
const minuto = String(data.getMinutes()).padStart(2, '0');
const segundo = String(data.getSeconds()).padStart(2, '0');
return `${ano}-${mes}-${dia} ${hora}:${minuto}:${segundo}`;
// Formata no fuso de Brasília para não depender do TZ do servidor
const fmt = new Intl.DateTimeFormat('sv-SE', {
timeZone: 'America/Araguaina',
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hour12: false
});
// sv-SE produz YYYY-MM-DD HH:mm:ss
return fmt.format(data).replace('T', ' ');
}
}