Problema com TimeZone - America/Sao_Paulo

Pessoal, estou tendo um problema de Calendar com timezone no Java. Não sei se alguém já passou por isso aqui, mas o problema é um tanto quanto estranho. Estou com um projetinho de console que usa Hibernate Annotations e Banco MySQL. Tudo está funcionando muito bem, exceto os campos de data.

Eu estou desenvolvendo meu projeto em uma máquina Windows com Java 6. Porém o projeto irá rodar em uma máquina com Debian, também Java 6 só que o fuso da máquina onde irá rodar o projeto é PST (Pacific Standard Time -08:00 horas). Então, para não ter problemas com fuso (quero sempre saber a hora que rodou pelo horário oficial brasileiro), estou usando a seguinte forma de se obter a data:

Calendar saoPauloDate = Calendar.getInstance(TimeZone.getTimeZone("America/Sao_Paulo"));

Quando eu rodo em minha máquina Windows esse código eu tenho a seguinte data:

21/2/2011 13:42 // Método de formatação de data omitido

No servidor com Debian, a hora também está voltando correta. Só que quando essa hora é persistida no Banco de Dados MySQL, volta-se 5 horas! Ou seja, se aqui em São Paulo é 10h00 e a aplicação roda, a data persistida é de 05h00 da madrugada!

Para tirar as dúvidas sobre o retorno de datas na minha máquina Windows e na máquina Debian, montei o seguinte código e rodei nos dois ambientes. Exportei via Eclipse como Runnable Jar File e executei usando o comando java -jar dateTest.jar. Veja o resultado abaixo:

Código rodado:

[code]import java.util.Calendar;
import java.util.TimeZone;

public class Main {

public static void main(String[] args) {

	Calendar systemDate = Calendar.getInstance();
	Calendar saoPauloDate = Calendar.getInstance(TimeZone.getTimeZone("America/Sao_Paulo"));
	Calendar brazilEastDate = Calendar.getInstance(TimeZone.getTimeZone("Brazil/East"));

	System.out.println("Sem Timezone: " + Main.getFormatedDate(systemDate));
	System.out.println("America/São_Paulo: " + Main.getFormatedDate(saoPauloDate));
	System.out.println("Brazil/East: " + Main.getFormatedDate(brazilEastDate));
}

private static String getFormatedDate(Calendar date) {
	StringBuffer formattedDate = new StringBuffer();
	formattedDate.append(date.get(Calendar.DAY_OF_MONTH)).append("/");
	formattedDate.append(date.get(Calendar.MONTH) + 1).append("/");
	formattedDate.append(date.get(Calendar.YEAR)).append(" ");
	formattedDate.append(date.get(Calendar.HOUR_OF_DAY)).append(":");
	formattedDate.append(date.get(Calendar.MINUTE));
	return formattedDate.toString();
}

}[/code]

Resultado na máquina Windows:

Sem Timezone: 21/2/2011 13:42 America/São_Paulo: 21/2/2011 13:42 Brazil/East: 21/2/2011 13:42

Resultado na máquina Debian:

Sem Timezone: 21/2/2011 8:49 America/São_Paulo: 21/2/2011 13:49 Brazil/East: 21/2/2011 13:49

Desconsiderem as diferenças de minutos. Quero que vejam que os resultados batem. Para finalizar o teste, rodei o comando date do Linux via SSH para obter a data e horário da máquina servidora e obtive o seguinte resultado:

Mon Feb 21 08:51:05 PST 2011

Chego a conclusão que o problema deva ser com o MySQL. Alguma configuração errada ou talvez anotação errada no Hibernate. Não sei. Alguém sabe o que pode estar acontecendo? É a primeira vez que trabalho com fuso horário no Java e estou apanhando demais.

Minha classe Hibernate que é persistida:

[code]@Entity
@Table(name = “tm_app_execution”)
public class AppExecution implements Serializable {

private static final long serialVersionUID = -1461955698187380141L;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "APP_EXECUTION_ID")
private Long appExecutionID;

@Column(name = "DATE_STARTED", nullable = false)
private Calendar dateStarted;

@Column(name = "DATE_FINISHED", nullable = true)
private Calendar dateFinished;

@Column(name = "EXECUTION_TIME", nullable = true)
private Integer executionTime;

@Column(name = "CONSOLE_PARAMS_USED", nullable = true)
private String consoleParamsUsed;

@Column(name = "HAVE_ERROR", nullable = true)
private Boolean haveError;

public Long getAppExecutionID() {
	return appExecutionID;
}

public void setAppExecutionID(Long appExecutionID) {
	this.appExecutionID = appExecutionID;
}

public Calendar getDateStarted() {
	return dateStarted;
}

public void setDateStarted(Calendar dateStarted) {
	this.dateStarted = dateStarted;
}

public Calendar getDateFinished() {
	return dateFinished;
}

public void setDateFinished(Calendar dateFinished) {
	this.dateFinished = dateFinished;
}

public Integer getExecutionTime() {
	return executionTime;
}

public void setExecutionTime(Integer executionTime) {
	this.executionTime = executionTime;
}

public String getConsoleParamsUsed() {
	return consoleParamsUsed;
}

public void setConsoleParamsUsed(String consoleParamsUsed) {
	this.consoleParamsUsed = consoleParamsUsed;
}

public Boolean getHaveError() {
	return haveError;
}

public void setHaveError(Boolean haveError) {
	this.haveError = haveError;
}

}[/code]

No MySQL estou usando InnoDB.

Resumindo o problema após toda essa explicação: Quando vou persistir um objeto Calendar usando Hibernate e Timezone America/Sao_Paulo em um banco de dados MySQL rodando em uma máquina Linux Debian configurado com o fuso horário PST, ele está gravando no horário PST ao invés de usar o fuso America/Sao_Paulo.

Se alguém precisar de mais alguma informação, é só pedir. Esse erro está bem chato de resolver.

Obrigado

o que retorna no sysdate do banco?

Vamos lá.

Executando o NOW() = 2011-02-21 09:27:07
Executando o CURDATE() = 2011-02-21 00:00:00
Executando o UTC_DATE() = 2011-02-21 17:28:23
Executando o UTC_TIMESTAMP() = 2011-02-21 17:29:25

Bem estranho.

mais uma coisa, posta aí o SQL que é gerado no INSERT pelo Hibernate.

Aí ferrou, porque o Hibernate usa PreparedStatments, da uma olhada:

insert into tm_app_execution (CONSOLE_PARAMS_USED, DATE_FINISHED, DATE_STARTED, EXECUTION_TIME, HAVE_ERROR) values (?, ?, ?, ?, ?)

Essa tabela também sofre updates, no entanto o problema com as datas está ocorrendo em todas as tabelas cuja colunas estão mapeadas como Calendar.

update tm_app_execution set CONSOLE_PARAMS_USED=?, DATE_FINISHED=?, DATE_STARTED=?, EXECUTION_TIME=?, HAVE_ERROR=? where APP_EXECUTION_ID=?

bom, provavelmente você terá que configurar o timezone também no mysql
http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html

configura o log para o nível de DEBUG e pega o que ele passa como parâmetro.

Recuperei os valores de insert do Hibernate, e para minha surpresa ele está inserindo a data errada. Não sei porque:

{dateFinished=null, consoleParamsUsed=, executionTime=null, dateStarted=2011-02-21 15:34:45, haveError=null, appExecutionID=29}

Rodei agora as 20h34!

[quote=lordcarlos]bom, provavelmente você terá que configurar o timezone também no mysql
http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html
[/quote]

Eu não tenho o controle total do Banco de Dados. É um shared server e por isso meus poderes são limitados. Mesmo assim, tem como eu setar o timezone somente para eu banco?

Outra alternativa seria eu usar um timezone diferente na aplicação de forma que bata com o horário de Brasília.

Valeu