Hummmm Não é o Java. Deixe marcado a opção no Windows “Ajustar automaticamente para o horário de verão” e rode o programa novamente. Se for isso eu prolongo o assunto e explico.
O Windows tem uma belíssima “cagada” de ter esta opção. O que ela faz: Diz que o seu TimeZone dentro do seu horário de verão é GMT-3. Só que o Java possui uma definição a parte dentro dele, que diz que é GMT-2.
Nunca mas nunca, defina TimeZone na mão. Sei por experiência própria que o melhor é jogar conforme as regras.
Se você está no Brasil dentro da Zona do Horário de Verão, você está em GMT-2. Logo, se o Windows abre esta opção e MENTE dizendo que você está em GMT-3, o erro está aí. Para confirmar isso é só olhar um mapa mundi com timezones, veja que o Brasil estará em GMT-3, mas dentro do horário de verão assumimos a posição de GMT-2. É Geografia e não informática.
Para fazer a conversão sem se preocupar com isso, você pode passá-la para string e realizar parse. Mas se quiser realmente entender o problema e resolver, dá uma olhada nesse artigo que escrevi desconsiderando o produto, o procedimento é genérico: http://www.mcfox.com.br/wiki/index.php?title=PSOffice_e_o_Horário_de_Verão
Demorei 2 transições para entender direito. Vale a pena descobrir o porquê.
O problema não é nenhuma das duas APIs, lê a parte funcional. Você precisa trabalhar em GMT-2 (se estiver dentro do horário de verão) e GMT-3 (fora dele).
Aplique o tzupdater (já aplicou)
Atualize o Sistema Operacional (no link que te passei tem uma página da MS sobre horário de verão + como atualizar em outros sistemas)
Deixe MARCADO a opção do “Ajustar automaticamente para o horário de verão”
Preste atenção neste último passo. Só o Windows possui essa opção. Nenhum outro sistema tem a opção de “mentir” que você está em GMT-3 depois do dia 18 de Outubro.
A sua API java.util.Date está pegando “BRT” pq o Sistema Operacional está mentindo para sua JVM. E seu Joda está Correto.
Como os dois possuem TimeZone diferentes (Joda/java.util.Date) haverá compensação no ato da conversão.