2009-07-29 19 views
2

Ich möchte Kalenderansicht machen, um Touch-Interaktion zu unterstützen. Also ich möchte neue benutzerdefinierte Kalenderansicht erstellen. Ich habe versucht, Mapping-Funktion zwischen View Offset und Real Date-Wert zu machen.Android java.util.Calendar - Zeitunterschied

Hier ist meine Idee: Wenn ich die Anzahl der Wochen seit Basisdatum berechnen kann (in meinem Fall 1989-12-31), ist es leicht zu wissen, Offset. HEIGHT_FOR_WEEK * NUM_OF_WEEK ist sehr einfache Berechnung , um genauen Offset zu wissen.

Mein Problem ist das: Zuerst bekam ich Millisekunden Wert von Basisdatum. Und ich setze die Millisekunden auf ein anderes Kalenderobjekt. Ich habe dasselbe Datum von diesem Objekt erwartet. Aber eigentlich war es anderes Datum.

mBaseDateInMillis = mBaseDate.getTimeInMillis(); 
mAnotherDate.setTimeInMillis(mBaseDateInMillis); 
/* I expect mBaseDate == mAnotherDate. 
* but it was different. 
*/ 

Hier ist mein Code:

public class CalendarCoordinate { 
    public static final long ONEWEEK_IN_MILLISECONDS = 60 * 60 * 24 * 7 * 1000; 
    public Calendar mBaseDate = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 
    public long mBaseDateInMillis = 0; 
    public Calendar mDate = new GregorianCalendar(TimeZone.getTimeZone("GMT")); 
    public int mWeekHeight = 30; 

    /** 
    * CTOR 
    */ 
    public CalendarCoordinate() { 
     /* Base date is 1989-12-31 0, 0, 0 
     * It was Sunday and offset 0 will be mapped onto this day. 
     */ 
     mBaseDate.set(Calendar.MILLISECOND, 0); 
     mBaseDate.set(1989, 12, 31, 0, 0, 0); 
     mBaseDateInMillis = mBaseDate.getTimeInMillis(); 
     Log.v(TAG, "BaseDate:" + mBaseDate.toString()); 
    } 

    /** 
    * Compute DATE from Y-Offset 
    * @param yOffset 
    * @return 
    */ 
    public Calendar dateFromYOffset(int yOffset) { 
     long nthWeeks = yOffset/mWeekHeight; 
     long millsSinceBaseDate = nthWeeks * ONEWEEK_IN_MILLISECONDS; 
     mDate.clear(); 
     mDate.set(Calendar.MILLISECOND, 0); 
     mDate.setTimeInMillis(mBaseDateInMillis + millsSinceBaseDate); 

     /* We SHOULD call to update mDate internal data structure. 
     * Java is really strange for this thing 
     **/ 
     mDate.getTimeInMillis(); 
     return mDate; 
    } 

    /** 
    * Compute Y-Offset from DATE 
    * @param date 
    * @return 
    */ 
    public long yOffsetFromDate(Calendar cal) { 
     long mills = cal.getTimeInMillis(); 
     long nthWeeks = (mills - mBaseDateInMillis)/ONEWEEK_IN_MILLISECONDS; 
     return nthWeeks * mWeekHeight; 
    } 
} 

Wer kann mir helfen? Ich bin kein guter Java-Programmierer.

Antwort

5

Diese Aussage verwirrt mich:

/* I expect mBaseDate == mAnotherDate. 
* but it was different. 
*/ 

Sind Sie tatsächlich auf Gleichheit zu überprüfen versucht durch den Vergleich machen: if (mBaseDate == mAnotherDate) {System.out.println ("Es sind die gleichen"); }

Wenn ja, ist Ihr Problem, dass Sie missverstehen, wie der Operator "==" in Java funktioniert. Es vergleicht Referenzen, anstatt die zugrunde liegenden Objektdaten zu vergleichen, und da dies verschiedene Objekte (mit denselben Werten) sind, die immer falsch sind. Für viele weitere Details, siehe Java Notes on comparison operators.

auch sehen diese Linien mir wirklich verdächtig:

/* We SHOULD call to update mDate internal data structure. 
* Java is really strange for this thing 
**/ 
mDate.getTimeInMillis(); 

ich wirklich überrascht wäre, wenn Android einen Fehler hatte die Sie auffordert, dies zu tun, aber ich denke, alles ist möglich. Was für Probleme hast du ohne diesen Anruf?

3

Dies ist, weil Sie die "equals" -Methode verwenden müssen, um verschiedene Objekte zu vergleichen. Mit dem Operator "==" können Sie feststellen, ob die Objekte identisch sind (sie befinden sich genau am gleichen Speicherort), während die Vergleichsfunktion "equals" Ihnen sagt, ob die beiden Objekte logisch gleichwertig sind.

0

tl; dr

long weeks = ChronoUnit.WEEKS.between (LocalDate.of (1989 , 12 , 31) , LocalDate.of (1990 , 1 , 14)); // Results: 2 

Vermeiden count-from-Epoche

Sie in einer Zählung-da-Epoche wie Millisekunden nicht funktionieren. Verwirrend, verschleiert Fehler und ignoriert Probleme wie Zeitzonen.

Lassen Sie eine gute Datum-Zeit-Bibliothek die Schwerarbeit in diesen Berechnungen durchführen.

java.time

Sie lästige alte Datum-Zeit-Klassen wie java.util.Calendar verwenden. Diese schlecht entworfenen Klassen wurden durch das java.time Framework ersetzt, das in Java 8 und höher integriert ist. Siehe Oracle Tutorial. Viel von dem Java.Zeit-Funktionalität wurde auf Java 6 & 7 in ThreeTen-Backport zurück-portiert und weiter an Android in ThreeTenABP angepasst.

ChronoUnit

Die ChronoUnit Klasse berechnet verstrichene Zeit wie die Anzahl der ganzen Wochen zwischen einem Paar von LocalDate (Datum nur, keine Zeit-of-Tag noch Zeitzone) Werte.

LocalDate start = LocalDate.of (2016 , 1 , 1); 
    LocalDate stop = start.plusDays (17); // Ex: 13 days = 1 week. 14 days = 2 weeks. 

    long weeks = ChronoUnit.WEEKS.between (start , stop); 

Dump zur Konsole.

System.out.println ("start: " + start + " | stop: " + stop + " | weeks: " + weeks); 

Start: 2016.01.01 | halt: 2016-01-18 | Wochen: 2

Wenn Sie eine Reihe von Wochen seit 1989-12-31 möchten, verwenden Sie das als das start Objekt oben gesehen.

LocalDate start = LocalDate.of(1989 , 12 , 31); 

Halboffen

Aber ich bemerken, dass Ihr Basisdatum der letzte Tag des Jahres ist. Tipp: Zeitspannen werden im Allgemeinen am besten mit dem Halboffenen Ansatz behandelt, bei dem der Anfang einschließlich ist, während die Endung exklusiv ist. Sie Mai wollen 1990-01-01 als Basisdaten verwenden (ich kenne nicht Ihre Geschäftslogik, also nur eine Vermutung meinerseits).

So Sie ersten zwei Wochen wäre dies (1. bis 15.):

long firstTwoWeeks = ChronoUnit.WEEKS.between (LocalDate.of (1990 , 1 , 1) , LocalDate.of (1990 , 1 , 15)); 

... eher als diese (31. bis 14.):

long firstTwoWeeks = ChronoUnit.WEEKS.between (LocalDate.of (1989 , 12 , 31) , LocalDate.of (1990 , 1 , 14)); 
Verwandte Themen