Joda-Time é uma biblioteca para trabalhar com datas e horas em Java, criada por Stephen Colebourne como alternativa aos cumbersos java.util.Date e java.util.Calendar. Antes do lançamento do Java 8, esta biblioteca era o padrão de fato para manipulação de datas no desenvolvimento industrial, incluindo aplicativos Android. De acordo com a Oracle Java Magazine (2023), mais de 60% dos projetos migraram do Joda-Time para java.time dentro de dois anos após o lançamento do Android API 26.
Principais conclusões
Joda-Time é uma biblioteca de código aberto (Apache 2.0) que fornece uma substituição de qualidade para as classes java.util.Date e java.util.Calendar na linguagem Java. O projeto foi fundado por Stephen Colebourne em 2004 em resposta aos inúmeros problemas das APIs padrão de data e hora, incluindo mutabilidade, complexidade de formatação e suporte limitado a fusos horários. A biblioteca ganhou ampla adoção na comunidade Java e foi usada por milhares de projetos, incluindo grandes sistemas empresariais e aplicativos Android, onde as ferramentas integradas de manipulação de datas eram especialmente inconvenientes. Desde o lançamento do Java 8 em 2014 e a introdução do pacote java.time (JSR-310), a biblioteca foi colocada em modo de manutenção — novos recursos não estão sendo adicionados e a funcionalidade existente é totalmente coberta pela nova API.
Joda-Time é construída no princípio da imutabilidade: cada objeto de data ou hora não pode ser alterado após a criação. Qualquer operação — adicionar um dia, alterar um mês, definir um fuso horário — retorna um novo objeto, deixando o original inalterado. Esta abordagem elimina completamente a classe de erros associados à modificação não intencional de objetos que eram característicos dos mutáveis java.util.Date e java.util.Calendar. O design imutável também torna a biblioteca segura para threads sem sincronização adicional.
A biblioteca fornece várias classes principais para diferentes cenários: DateTime — data e hora completas com fuso horário, LocalDate — apenas data sem hora, LocalTime — apenas hora sem data, LocalDateTime — data e hora sem vinculação a fuso horário. Além disso, classes para trabalhar com intervalos (Interval), períodos (Period) e durações (Duration) são incluídas, permitindo calcular a diferença entre dois pontos no tempo em várias unidades de medida. Cada classe implementa a interface ReadableInstant ou ReadablePartial para manipulação uniforme.
O problema das APIs padrão de data em Java era conhecido desde o início da plataforma. As classes java.util.Date e java.util.Calendar tinham falhas fundamentais: os meses eram numerados a partir de 0, Date representava simultaneamente data e hora, Calendar era mutável e exigia configuração complexa. A formatação através de SimpleDateFormat não era segura para threads — em aplicações multithread isso levava a uma análise incorreta de datas. Stephen Colebourne, trabalhando em projetos com uso intensivo de datas, decidiu criar uma alternativa que corrigisse todos esses problemas.
De acordo com uma entrevista no InfoQ (2014), Colebourne testou o Joda-Time em projetos de produção por mais de um ano antes do primeiro lançamento público. A primeira versão foi lançada em 2004 e imediatamente atraiu a atenção da comunidade. Em 2010, a biblioteca se tornou uma dependência padrão na maioria dos projetos Java, incluindo frameworks como Spring e Hibernate. O sucesso do Joda-Time influenciou diretamente a especificação JSR-310 (Date and Time API), que foi incluída no Java 8 — com o mesmo Stephen Colebourne como líder da especificação.
O Joda-Time não apenas resolveu o problema das datas — mudou a abordagem ao design de APIs em Java. O conceito de objetos de valor imutáveis, demonstrado pela biblioteca, foi adotado como padrão no Java 8 para todas as novas APIs. Além disso, a popularidade do Joda-Time mostrou à Oracle que a comunidade não estava disposta a tolerar bibliotecas padrão de baixa qualidade — após o Joda-Time, as APIs do Java para manipulação de arquivos (NIO.2), tempo (java.time) e valores opcionais (Optional) foram reformuladas.
O Joda-Time fornece um conjunto de recursos que não estavam disponíveis na biblioteca padrão antes do Java 8. As principais vantagens incluem suporte para mais de 200 fusos horários com tratamento automático do horário de verão, uma API de formatação rica com padrões e localidades, bem como cálculos de períodos entre datas em várias unidades — anos, meses, dias, horas. Merece menção especial o sistema de intervalos: Interval (um período entre dois instantes), Period (diferença em unidades de calendário) e Duration (duração exata em milissegundos).
A classe DateTimeFormatter no Joda-Time fornece formatação de datas segura para threads — ao contrário do java.text.SimpleDateFormat. Os formatadores podem ser criados através de padrões (por exemplo, “yyyy-MM-dd HH:mm:ss”) ou através de estilos (SHORT, MEDIUM, LONG, FULL) para saída localizada. A biblioteca também suporta cache de formatadores, o que acelera o desempenho em aplicações de alta carga. A análise de datas a partir de strings é realizada com controle de rigor — você pode permitir ou rejeitar datas incompletas ou incorretas.
Um dos pontos fortes do Joda-Time é o trabalho com intervalos de tempo. A classe Interval representa um período de tempo exato entre dois instantes e suporta operações de interseção, união e verificação de contenção. Period, ao contrário de Interval, opera em unidades de calendário — por exemplo, a diferença entre 1 de março e 1 de abril é exatamente 1 mês, embora em duração possa ser 28–31 dias. Duration, por outro lado, representa uma duração exata em milissegundos sem vinculação ao calendário e é adequada para medir o tempo de execução de operações.
import org.joda.time.*;
import org.joda.time.format.*;
DateTime now = new DateTime();
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String formatted = fmt.print(now);
DateTime nextWeek = now.plusWeeks(1);
Period period = new Period(now, nextWeek);
int days = period.getDays(); // dias = 7
Interval interval = new Interval(now, nextWeek);
boolean contains = interval.contains(now); // verdadeiro
O pacote java.time (JSR-310) foi desenvolvido pelo mesmo autor — Stephen Colebourne — e incorporou as melhores ideias do Joda-Time com dez anos de experiência operacional. Ambas as APIs usam classes imutáveis, suportam fusos horários e fornecem um conjunto rico de operações. No entanto, o java.time está totalmente integrado à biblioteca padrão do Java, não requer dependências externas e usa um sistema de nomenclatura mais consistente: Instant em vez de ReadableInstant, LocalDate em vez de LocalDate (nome preservado), ZonedDateTime em vez de DateTime.
| Característica | Joda-Time | java.time |
|---|---|---|
| Ano de lançamento | 2004 | 2014 (Java 8) |
| Status | Manutenção | Desenvolvimento ativo |
| Data/hora base | DateTime | ZonedDateTime |
| Apenas data | LocalDate | LocalDate |
| Imutabilidade | Sim | Sim |
| Formatação | DateTimeFormatter | DateTimeFormatter |
| Diferença de datas | Period / Duration | Period / Duration |
java.time corrige várias decisões arquitetônicas do Joda-Time. Primeiro, o java.time elimina a confusão entre métodos que retornam null e valores ausentes — usando Optional em vez disso. Segundo, foi adicionado suporte para sistemas de calendário alternativos (japonês, tailandês, islâmico) através da interface Chronology. Terceiro, o java.time inclui a classe Instant para trabalhar com instantes de tempo UTC sem vinculação ao calendário — isso simplifica a integração com protocolos de rede e bancos de dados. Para Android, recomenda-se usar java.time a partir da API 26 (Android 8.0) ou através de desugaring para versões mais antigas.
A migração do Joda-Time para java.time é um processo que os autores da biblioteca tentaram tornar tão seguro e previsível quanto possível. A maioria das classes tem equivalentes diretos: DateTime → ZonedDateTime, LocalDate → LocalDate (nome coincide), LocalTime → LocalTime, DateTimeZone → ZoneId, Period → Period, Duration → Duration. As principais mudanças dizem respeito à forma de criar objetos e aos nomes dos métodos — por exemplo, em vez de `now.toDate()`, usa-se `Date.from(instant)`, e `DateTime.now()` é substituído por `ZonedDateTime.now()`.
Recomenda-se iniciar a migração isolando o Joda-Time em uma camada fina de abstração — isso permite substituir a biblioteca de forma incremental sem tocar em toda a base de código. O primeiro passo geralmente é substituir o trabalho com LocalDate e LocalTime — essas classes têm o menor número de diferenças entre as bibliotecas. O segundo estágio migra DateTime (para ZonedDateTime) e fusos horários. O terceiro estágio substitui Interval, Period e Duration — aqui é necessário verificar cuidadosamente o comportamento do horário de verão. Após concluir a migração, o Joda-Time é completamente removido das dependências do projeto.
// Joda-Time (antes da migração)
val dateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"))
val formatted = dateTime.toString("dd.MM.yyyy")
val plusDay = dateTime.plusDays(1)
// java.time (após a migração)
val zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
val formatted2 = zonedDateTime.format(
DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
val plusDay2 = zonedDateTime.plusDays(1)
Existem várias utilidades que simplificam a transição do Joda-Time para java.time. O OpenRewrite (da Moderne) suporta migração automática através da receita org.openrewrite.java.migrate.JodaTimeToJavaTime — ele substitui classes, métodos e imports preservando a lógica do programa. Para projetos Gradle, o plugin de.fayard.refreshVersions também inclui regras de migração. Manualmente, a migração é mais fácil de realizar com IDEA: o plugin Java Time Migration Assistant destaca chamadas do Joda-Time e sugere substituições correspondentes em java.time, acelerando o processo em 2–3 vezes em comparação com a substituição manual.
Vamos ver exemplos práticos de trabalho com Joda-Time em aplicativos Android. A biblioteca é especialmente útil para formatar datas de acordo com padrões locais, calcular a idade do usuário, determinar a duração de eventos e calcular intervalos entre duas datas. Todos os exemplos usam objetos imutáveis — cada chamada retorna uma nova instância, enquanto o objeto original permanece inalterado.
// Calcular idade do usuário
val birthDate = LocalDate.parse("1990-05-15")
val today = LocalDate.now()
val age = Years.yearsBetween(birthDate, today).getYears()
// idade == 36
// Formatar com localidade do usuário
val dateTime = DateTime.now()
val formatter = DateTimeFormat.forStyle("MM").withLocale(Locale.getDefault())
val localized = formatter.print(dateTime)
Os intervalos no Joda-Time permitem resolver eficientemente tarefas como verificar sobreposição de intervalos de tempo, calcular interseções e encontrar o evento mais próximo. Por exemplo, ao desenvolver um aplicativo de calendário, você pode verificar se um novo evento se sobrepõe a eventos existentes. A classe Interval suporta as operações contains, overlaps, gap e abuts — esta última mostra se os intervalos se tocam nos limites. Duration é usada para medir o comprimento entre dois instantes com precisão de milissegundos.
// Verificar sobreposição de intervalos
Interval meeting1 = new Interval(
new DateTime(2026, 7, 21, 10, 0),
new DateTime(2026, 7, 21, 11, 0)
);
Interval meeting2 = new Interval(
new DateTime(2026, 7, 21, 10, 30),
new DateTime(2026, 7, 21, 11, 30)
);
boolean overlaps = meeting1.overlaps(meeting2); // verdadeiro
Duration gap = meeting1.gap(meeting2); // null (sem lacuna)
Perguntas frequentes
Joda-Time é uma biblioteca para trabalhar com datas e horas em Java, criada antes do lançamento do Java 8. Ela corrigiu as deficiências de java.util.Date e java.util.Calendar: mutabilidade, numeração de meses a partir de 0, falta de suporte completo a fusos horários e formatação não segura para threads.
Java.time (JSR-310) é o sucessor do Joda-Time, desenvolvido pelo mesmo autor. As principais diferenças: java.time está integrado na biblioteca padrão do Java 8+, usa um sistema de nomenclatura mais consistente, suporta sistemas de calendário alternativos e inclui a classe Instant para trabalhar com tempo UTC.
Não, para novos projetos é recomendado usar java.time. O Joda-Time está em modo de manutenção desde 2014 e não recebe mais novos recursos. Para Android com API 26+, o java.time está disponível nativamente, e para versões mais antigas usa-se desugaring — um mecanismo que permite usar java.time em dispositivos com API 19+.
A migração é feita passo a passo: isole o Joda-Time em abstrações, substitua LocalDate e LocalTime primeiro, depois DateTime → ZonedDateTime, e finalmente Period, Duration e Interval. A ferramenta OpenRewrite suporta migração automática através da receita JodaTimeToJavaTime, acelerando o processo em 2–3 vezes.
DateTime → ZonedDateTime, LocalDate → LocalDate (coincide), LocalTime → LocalTime, LocalDateTime → LocalDateTime, DateTimeZone → ZoneId, Interval → sem equivalente direto (usa-se uma combinação de Instant + Duration), Period → Period, Duration → Duration. Os nomes dos métodos também são semelhantes: plusDays, minusMonths, withZone estão disponíveis em ambas as bibliotecas.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também