Opa boa boa excelentes pontos esses, me fizeram pensar em algumas coisas:
De fato ChronoUnit e ChronoField são descritas de forma bem parecida, eu fui dar uma olhada no JavaDoc delas e saca só:
public enum ChronoField implements TemporalField {
public enum ChronoUnit implements TemporalUnit {
A ChronoField
é um "conjunto de campos padrão" e ChronoUnit
é descrita como "um conjunto padrão de unidades de período de datas".
De fato por descrição são praticamente a mesma coisa.
Mas vamos imaginar que eu quero somar 10 dias na data atual, eu faria algo mais ou menos assim:
LocalDate value = LocalDate.now().plus(10, ChronoUnit.DAYS);
Como a assinatura do método plus()
espera receber um TemporalAmount
ou um valor inteiro e um TemporalUnit
então só é possível utilizar ChronoUnit
que implementa a interface (é um) TemporalUnit
.
Da mesma forma, vamos dizer que eu queira saber em que mês estamos, eu teria de fazer
LocalDate.now().get(ChronoField.MONTH_OF_YEAR);
Nesse caso o método get()
espera receber um TemporalField
, logo não é possível utilizar ChronoUnit
e por isso utilizamos ChronoField
que implementa a interface (é um) TemporalField
.
Quanto a semântica, penso o seguinte:
ChronoUnit
Uma unidade deve ser utilizada para medir uma quantidade de tempo - anos, meses, dias, horas, minutos, segundos. Por exemplo, o segundo é uma unidade do S.I.
ChronoField
Por outro lado, os campos são como os humanos geralmente se referem ao tempo, que é em partes. Se você olhar para um relógio digital, os segundos contam de 0 a 59 e depois voltam para 0 novamente.
Este é um campo - "segundo do minuto" neste caso, formado pela contagem de segundos dentro de um minuto.
Da mesma forma, os dias são contados dentro de um mês e os meses dentro de um ano. Para definir um ponto completo na linha do tempo, você precisa ter um conjunto de campos vinculados, por exemplo:
- segundo de minuto
- minuto-a-hora
- hora do dia
- dia do mês
- mês do ano
- ano (-de-para-sempre)
A API ChronoField expõe as duas partes do segundo do minuto.Podemos utilizar getBaseUnit()
para obter "segundos" e getRangeUnit()
para obter "minutos".
A parte Chrono do nome refere-se ao fato de que as definições são cronologicamente neutras. Especificamente, isso significa que a unidade ou campo tem significado apenas quando associado a um sistema de calendário ou cronologia. Um exemplo disso é a cronologia copta, onde há 13 meses em um ano. Apesar de ser diferente do sistema de calendário civil/ISO comum, a constante ChronoField.MONTH_OF_YEAR ainda pode ser usada.
As interfaces TemporalUnit e TemporalField fornecem a abstração de nível mais alto, permitindo que unidades/campos que não são cronologicamente neutros sejam adicionados e processados.
Não sei se ficou mais claro ou mais confuso, mas pelo menos acho que eu entendi melhor um pouco sobre essa duas enums e sua utilização.
Penso que talvez pudessem ter feito uma única enum pra tudo, porém acredito que tiverem alguns motivos pra ter as duas, sendo o primeiro deles querer separar unidades de campos para que aquele que lê o código possa entender mais rapidamente do que se trata aquele código.