Domanda

Qualcuno potrebbe avvisare l'attuale "migliore pratica" intorno ai tipi Date e Calendar .

Quando si scrive un nuovo codice, è preferibile preferire sempre Calendar rispetto a Date , oppure ci sono circostanze in cui Date è il tipo di dati più appropriato ?

È stato utile?

Soluzione

La data è una classe più semplice ed è presente principalmente per motivi di compatibilità con le versioni precedenti. Se è necessario impostare date particolari o eseguire l'aritmetica della data, utilizzare un calendario. I calendari gestiscono anche la localizzazione. Le precedenti funzioni di modifica della data di Date sono state deprecate.

Personalmente tendo a usare il tempo in millisecondi come lungo (o lungo, a seconda dei casi) o il calendario quando c'è una scelta.

Sia la data che il calendario sono mutabili, il che tende a presentare problemi quando si utilizza una delle API.

Altri suggerimenti

Il modo migliore per il nuovo codice (se la tua politica consente il codice di terze parti) è utilizzare la libreria Joda Time .

Entrambi, Date e Calendar , hanno così tanti problemi di progettazione che non sono nemmeno buone soluzioni per il nuovo codice.

  • Date e Calendar sono in realtà lo stesso concetto fondamentale (entrambi rappresentano un istante nel tempo e sono avvolti attorno a un < codice> lungo ).

  • Si potrebbe sostenere che Calendar è in realtà anche più rotto di Date , poiché sembra offrire fatti concreti sulle cose come il giorno della settimana e l'ora del giorno, mentre se cambi la sua proprietà timeZone , il calcestruzzo si trasforma in blancmange! Nessuno degli oggetti è davvero utile come archivio di anno-mese-giorno o ora del giorno per questo motivo.

  • Usa Calendario solo come una calcolatrice che, quando vengono dati gli oggetti Date e TimeZone , eseguirà i calcoli per te. Evita il suo utilizzo per la digitazione delle proprietà in un'applicazione.

  • Usa SimpleDateFormat insieme a TimeZone e Date per generare stringhe di visualizzazione.

  • Se ti senti avventuroso, usa Joda-Time, sebbene sia IMHO inutilmente complicato e sarà presto sostituito dall'API di data JSR-310 in ogni caso.

  • Ho già risposto che non è difficile inserire la tua classe YearMonthDay , che utilizza Calendar sotto il cofano per i calcoli della data. Sono stato sottoposto a downgrade per il suggerimento, ma credo ancora che sia valido perché Joda-Time ( e JSR-310 ) sono davvero così complicati per la maggior parte dei casi d'uso.

La data è la migliore per la memorizzazione di un oggetto data. È quello persistente, quello serializzato ...

Il calendario è il migliore per manipolare le date.

  

Nota: a volte preferiamo anche java.lang.Long over Date, perché Date è modificabile e quindi non è sicuro per i thread. Su un oggetto Date, utilizzare setTime () e getTime () per alternare tra i due. Ad esempio, una data costante nell'applicazione (esempi: zero 1970/01/01 o un END_OF_TIME applicativo impostato su 2099/12/31; quelli sono molto utili per sostituire i valori null come ora di inizio e ora di fine, in particolare quando li persistete nel database, dato che SQL è così peculiare con i null).

In genere uso Date, se possibile. Sebbene sia mutabile, i mutatori sono in realtà deprecati. Alla fine si avvolge sostanzialmente un lungo che rappresenterebbe la data / ora. Al contrario, utilizzerei i calendari se dovessi manipolare i valori.

Puoi pensarlo in questo modo: usi StringBuffer solo quando hai bisogno di stringhe che puoi facilmente manipolare e poi convertirle in stringhe usando il metodo toString (). Allo stesso modo, uso Calendar solo se devo manipolare i dati temporali.

Per la migliore pratica, tendo a utilizzare oggetti immutabili il più possibile al di fuori del modello di dominio . Riduce significativamente le possibilità di effetti collaterali ed è fatto per te dal compilatore, piuttosto che un test JUnit. Usi questa tecnica creando campi finali privati ?? nella tua classe.

E tornando all'analogia StringBuffer. Ecco un codice che mostra come convertire tra Calendario e Data

String s = "someString"; // immutable string
StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer
buf.append("x");
assertEquals("someStringx", buf.toString()); // convert to immutable String

// immutable date with hard coded format.  If you are hard
// coding the format, best practice is to hard code the locale
// of the format string, otherwise people in some parts of Europe
// are going to be mad at you.
Date date =     new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02");

// Convert Date to a Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);

// mutate the value
cal.add(Calendar.YEAR, 1);

// convert back to Date
Date newDate = cal.getTime();

// 
assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);

Date dovrebbero essere usati come punti immutabili nel tempo; I Calendar sono mutabili e possono essere passati e modificati se devi collaborare con altre classi per trovare una data finale. Considerali analoghi a String e StringBuilder e capirai come ritengo che dovrebbero essere usati.

(E sì, so che Date non è in realtà tecnicamente immutabile, ma l'intenzione è che non dovrebbe essere mutabile, e se nulla chiama i metodi deprecati allora è così.)

tl;dr

advise the current "best practice" around Date and Calendar

is it best to always favour Calendar over Date

Avoid these legacy classes entirely. Use java.time classes instead.

  • For a moment in UTC, use Instant
    (the modern equivalent of Date)
  • For a moment in a particular time zone, use ZonedDateTime
    (the modern equivalent of GregorianCalendar)
  • For a moment in a particular offset-from-UTC, use OffsetDateTime
    (no equivalent in legacy classes)
  • For a date-time (not a moment) with unknown time zone or offset, use LocalDateTime
    (no equivalent in legacy classes)

Details

The Answer by Ortomala Lokni is right to suggest using the modern java.time classes rather than the troublesome old legacy date-time classes (Date, Calendar, etc.). But that Answer suggests the wrong class as equivalent (see my comment on that Answer).

Using java.time

The java.time classes are a vast improvement over the legacy date-time classes, night-and-day difference. The old classes are poorly-designed, confusing, and troublesome. You should avoid the old classes whenever possible. But when you need to convert to/from the old/new, you can do so by calling new methods add to the old classes.

For much more information on conversion, see my Answer and nifty diagram to another Question, Convert java.util.Date to what “java.time” type?.

Searching Stack Overflow gives many hundreds of example Questions and Answers on using java.time. But here is a quick synopsis.

Instant

Get the current moment with an Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = Instant.now();

ZonedDateTime

To see that same simultaneous moment through the lens of some particular region’s wall-clock time, apply a time zone (ZoneId) to get a ZonedDateTime.

Time zone

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();

Offset

A time zone is a region’s history of changes in its offset-from-UTC. But sometimes you are given only an offset without the full zone. In that case, use the OffsetDateTime class.

ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );

Use of a time zone is preferable over use of a mere offset.

LocalDateTime

The “Local” in the Local… classes means any locality, not a particular locality. So the name can be counter-intuitive.

LocalDateTime, LocalDate, and LocalTime purposely lack any information about offset or time zone. So they do not represent actual moments, they are not points on the timeline. When in doubt or in confusion, use ZonedDateTime rather than LocalDateTime. Search Stack Overflow for much more discussion.

Strings

Do not conflate date-time objects with strings that represent their value. You can parse a string to get a date-time object, and you can generate a string from a date-time object. But the string is never the date-time itself.

Learn about standard ISO 8601 formats, used by default in the java.time classes.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

With Java 8, the new java.time package should be used.

Objects are immutable, time zones and day light saving are taken into account.

You can create a ZonedDateTime object from an old java.util.Date object like this:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());

I always advocate Joda-time. Here's why.

  1. the API is consistent and intuitive. Unlike the java.util.Date/Calendar APIs
  2. it doesn't suffer from threading issues, unlike java.text.SimpleDateFormat etc. (I've seen numerous client issues relating to not realising that the standard date/time formatting is not thread-safe)
  3. it's the basis of the new Java date/time APIs (JSR310, scheduled for Java 8. So you'll be using APIs that will become core Java APIs.

EDIT: The Java date/time classes introduced with Java 8 are now the preferred solution, if you can migrate to Java 8

A little bit late at party, but Java has a new Date Time API in JDK 8. You may want to upgrade your JDK version and embrace the standard. No more messy date/calendar, no more 3rd party jars.

Date should be re-developed. Instead of being a long interger, it should hold year, month, date, hour, minute, second, as separate fields. It might be even good to store the calendar and time zone this date is associated with.

In our natural conversation, if setup an appointment at Nov. 1, 2013 1pm NY Time, this is a DateTime. It is NOT a Calendar. So we should be able to converse like this in Java as well.

When Date is stored as a long integer (of mili seconds since Jan 1 1970 or something), calculating its current date depends on the calendar. Different calendars will give different date. This is from the prospective of giving an absolute time (eg 1 trillion seconds after Big Bang). But often we also need a convenient way of conversation, like an object encapsulating year, month etc.

I wonder if there are new advances in Java to reconcile these 2 objectives. Maybe my java knowledge is too old.

Btw "date" is usually tagged as "obsolete / deprecated" (I dont know exactly why) - something about it is wrote there Java: Why is the Date constructor deprecated, and what do I use instead?

It looks like it's a problem of the constructor only- way via new Date(int year, int month, int day), recommended way is via Calendar and set params separately .. (Calendar cal = Calendar.getInstance(); )

I use Calendar when I need some specific operations over the dates like moving in time, but Date I find it helpful when you need to format the date to adapt your needs, recently I discovered that Locale has a lot of useful operations and methods.So I'm using Locale right now!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top