Come ottenere il numero corretto di ore tra le date di Joda?

Voglio ottenere tutte le ore di ora legale (DST) tra due date.

Questo è il mio codice di esempio:

public static void main(String[] args) { Date startDate = new Date(); Calendar startCalendar = Calendar.getInstance(); startCalendar.setTime(startDate); startCalendar.set(2014, 2, 1, 0, 0, 0); startCalendar.set(Calendar.MILLISECOND, 0); Date endDate = new Date(); Calendar endCalendar = Calendar.getInstance(); endCalendar.setTime(endDate); endCalendar.set(2014, 2, 31, 0, 0, 0); endCalendar.set(Calendar.MILLISECOND, 0); DateTime startDateTime = new DateTime(startCalendar); DateTime endDateTime = new DateTime(endCalendar).plusDays(1); Hours hours = Hours.hoursBetween(startDateTime, endDateTime); // actual is 744 System.out.println("Expected: 743, actual: " + hours.getHours()); } 

Beh, ovviamente mi manca qualcosa ma non riesco a individuare il mio errore.

Il problema principale è che non si riesce a specificare un fuso orario .

Quando eseguo il tuo codice qui a Seattle, ottengo 743 ore nel mese di marzo 2014. Perché? A causa del mio fuso orario predefinito. Qui, sulla costa occidentale degli Stati Uniti, l’ ora legale inizia il 9 marzo 2014, domenica, alle 02:00. Vedi questa pagina, le date di cambio orario nel 2014 . Quindi quel giorno, il 9, è effettivamente lungo 23 ore invece di 24.

Ma se qualcuno in Islanda ha eseguito lo stesso identico codice, otterrebbe 744 . Perché? Perché il popolo islandese è troppo intelligente per preoccuparsi dell’assurdità dell’ora legale.

Inoltre, come buona abitudine, dovresti chiamare il metodo Joda-Time con withTimeAtStartOfDay() quando provi a lavorare con giorni. Precedentemente abbiamo usato i metodi di midnight di Joda-Time, ma quelli sono deprecati perché alcuni giorni in alcuni calendari non hanno una mezzanotte .

Suggerimento: prestare attenzione ai metodi Joda-Time denominati con lo standard , che il documento spiega significa un’assunzione di giorni di 24 ore. In altre parole, questi metodi ignorano i turni dell’ora legale.

Ecco alcuni esempi di codice che utilizzano Joda-Time 2.3 in Java 7.

 // © 2013 Basil Bourque. This source code may be used freely forevery by anyone taking full responsibility for doing so. // Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classs bundled with Java 7 and earlier. // http://www.joda.org/joda-time/ // Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8. // JSR 310 was inspired by Joda-Time but is not directly based on it. // http://jcp.org/en/jsr/detail?id=310 // By default, Joda-Time produces strings in the standard ISO 8601 format. // https://en.wikipedia.org/wiki/ISO_8601 // Time Zone list: http://joda-time.sourceforge.net/timezones.html org.joda.time.DateTimeZone seattleTimeZone = org.joda.time.DateTimeZone.forID("America/Los_Angeles"); org.joda.time.DateTimeZone icelandTimeZone = org.joda.time.DateTimeZone.forID("Atlantic/Reykjavik"); // Switch between using 'seattleTimeZone' and 'icelandTimeZone' to see different results (23 vs 24). org.joda.time.DateTime theNinth = new org.joda.time.DateTime( 2014, 3, 9, 0, 0, seattleTimeZone ) ; // Day when DST begins. org.joda.time.DateTime theTenth = theNinth.plusDays( 1 ); // Day after DST begins. // Using "hoursBetween()" method with a pair of DateTimes. org.joda.time.Hours hoursObject = org.joda.time.Hours.hoursBetween( theNinth.withTimeAtStartOfDay(), theTenth.withTimeAtStartOfDay() ); int hoursInt = hoursObject.getHours(); System.out.println( "Expected 23 from hoursInt, got: " + hoursInt ); // Using an Interval. org.joda.time.Interval interval = new Interval( theNinth.withTimeAtStartOfDay(), theTenth.withTimeAtStartOfDay() ); System.out.println( "Expected 23 from interval, got: " + org.joda.time.Hours.hoursIn(interval).getHours() ); // Using a Period with Standard days. org.joda.time.Period period = new org.joda.time.Period( theNinth.withTimeAtStartOfDay(), theTenth.withTimeAtStartOfDay() ); org.joda.time.Hours standardHoursObject = period.toStandardHours(); System.out.println( "Expected 24 from standardHoursObject, got: " + standardHoursObject.getHours() ); 

Benvenuti nel caos che è la gestione della data / ora. Il tuo problema sono i fusi orari. In particolare, qualunque fuso orario ti trovi osserva l’ora legale e l’interruttore (molla in avanti) si verifica durante l’intervallo, che lo accorcia di un’ora. Vedi questo codice.

 public class DateTimeTest { public static void main(String[] args) { DateTime startDateTime = new DateTime() .withYear(2014) .withMonthOfYear(3) .withDayOfMonth(1) .withHourOfDay(0) .withMinuteOfHour(0) .withSecondOfMinute(0) .withMillisOfSecond(0) .withZone(DateTimeZone.forID("US/Eastern")); DateTime endDateTime = new DateTime() .withYear(2014) .withMonthOfYear(3) .withDayOfMonth(31) .withHourOfDay(0) .withMinuteOfHour(0) .withSecondOfMinute(0) .withMillisOfSecond(0) .withZone(DateTimeZone.forID("US/Eastern")) .plusDays(1); System.out.println("Expected 744, got: " + Hours.hoursBetween(startDateTime, endDateTime).getHours()); // 743 DateTime startUtc = startDateTime.withZoneRetainFields(DateTimeZone.UTC); DateTime endUtc = endDateTime.withZoneRetainFields(DateTimeZone.UTC); System.out.println("Expected 744, got: " + Hours.hoursBetween(startUtc, endUtc).getHours()); // 744 } } 

Nemmeno io riesco a capirlo (ma al tempo di Joda?), Ma potresti aggirare il problema. La differenza in millisecondi diviso per 3600000L dovrebbe essere il numero esatto di ore. Ho provato e ottenuto 743.