2017-01-26 15 views
11

Poniższy kod podaje inny wynik na Nougat i pre-Nougat. Spójrz i spróbuj sam, jeśli chcesz. Byłbym wdzięczny, gdyby ktoś mógł mi wyjaśnić, dlaczego i dać rozwiązanie.Zestaw kalendarza gregoriańskiegoFirstDayOfWeek nie wpływa na WEEK_OF_YEAR na pre Nougat

Chcę uzyskać prawidłową wartość WEEK_OF_YEAR, zależną od pierwszego dnia tygodnia, we wszystkich wersjach systemu Android. Mam aplikację arkusza czasu i bardzo często używam kalendarza gregorianCalendar, więc nie mam zamiaru przełączać się na inną klasę/bibliotekę.

//default first day of the week is Monday for replication. I live in the Netherlands, it's weird. 
    Locale l = new Locale("nl", "NL"); 

    GregorianCalendar test = new GregorianCalendar(l); 
    test.set(Calendar.YEAR, 2017); 
    test.set(Calendar.MONTH, 0); 
    test.set(Calendar.DAY_OF_MONTH, 29);//this is a Sunday 

    int week = test.get(Calendar.WEEK_OF_YEAR);//should be 4 
    test.setFirstDayOfWeek(1);//Set it to Sunday 
    int week2 = test.get(Calendar.WEEK_OF_YEAR);//should be 5 but is 4 below nougat??? 
+0

dzięki za wyjaśnienia. Nie sądzę, że moja odpowiedź będzie ci teraz przydatna, poza ogólnym skinieniem w kierunku problemu (aplikacja dopasowująca Nougat i ustawienia regionalne systemu). Aby przyciągnąć lepsze odpowiedzi, być może możesz wyjaśnić coś więcej. Czy ustawienie Locale w przykładowym kodzie służy tylko do replikowania problemu lub czy jest to coś, co chciałbyś zrobić w swojej aplikacji? –

+0

Dzięki i tak. Lokalizacja ma jedynie na celu odtworzenie problemu. –

Odpowiedz

3

Jeśli spojrzeć na release notes for Nougat widać, że nie jest wzmocnione wsparcie dla ustawień regionalnych.

Szczególnie

Przed Android 7.0, Android mogłyby nie zawsze z powodzeniem dopasować aplikacji i systemu lokalizacje.

Ja też zauważyłem to na moim własnym urządzeniu. Mój telefon ma ustawiony język angielski (Australia). Przed nugat

DateTimeFormat.forPattern("dd MMMM").print(new LocalDate(2017,1,29)); 

będzie drukować 29 Jan (bez kropki/okres), ale po Nugat drukuje to 29 Jan. (z okresu).

Chociaż trudno mi podać dokładne dane, wydaje się, że tak właśnie dzieje się w twoim przypadku. Po Nougacie telefon jest w stanie lepiej dopasować ustawienia aplikacji i systemu, w tym pierwszy dzień tygodnia dla Twojego ustawienia regionalnego. W każdym przypadku, przejście przez debugger w celu znalezienia głównej przyczyny nie zadziała, ponieważ wywołanie jest obsługiwane wewnątrz libcore, a nie w klasie Java ujawnionej w kodzie źródłowym.

Jeśli urządzenie Android jest nieprawidłowo raportowania pierwszy dzień roku/pierwszy tydzień roku, nie byłoby niewiele można zrobić poza obejść:

if (android.os.Build.VERSION.SDK_INT < 24) { 
    //pre-Nougat logic 
} 
else { 
    //Nougat/post-Nougat logic 
} 

Można też może spróbować użyć enhanced replacement for GregorianCalendar (dodane w SDK 24), aby naprawić swój problem.

Jeśli używasz klas takich jak Joda-time lub korzystasz z nowych klas JSR-310 (przez Backport ThreeTen), możesz być w stanie uzyskać to, czego chcesz, bez konieczności pracy nad GregorianCalendar. Ogólnie rzecz biorąc, te klasy są dużo łatwiejsze w użyciu i mniej podatne na błędy. Wielu programistów zrezygnowało już z java.util.Calendar i java.util.Date z powodu takich problemów. Proszę zobaczyć odpowiedź to this canonical question Szczegółowe

Jeśli było użyć Joda, można użyć LocalDate.fromCalendarFields(test) konwertować obiekt GregorianCalendar w LocalDate. Zajęcia te korzystają ze standardu ISO, gdzie pierwszy dzień tygodnia to zawsze poniedziałek. Następnie napiszesz na nich logikę, którą chcesz. Następnie problem z GregorianCalendar zostanie "wyizolowany" w zwykły problem z pobieraniem pierwszego tygodnia roku dla danego Locale. Jeśli Twoja aplikacja zawiera połączenia z serwerem, możesz zamiast tego serwować pierwszy dzień tygodnia z połączenia API.

Aktualizacja: zachowanie stref czasowych

Uwaga została zaktualizowana w Android O:

Dodatkowe zmiany związane umiędzynarodowienia-locale i są następujące:

Czas nazwa strefa parsowanie się nie zmieniło. Wcześniej urządzenia z systemem Android używały wartości zegara systemowego próbkowanego podczas rozruchu, aby buforować nazwy stref czasowych używanych do analizowania czasów dat. W efekcie może to negatywnie wpłynąć na parsowanie, jeśli zegar systemowy był nieprawidłowy podczas startu systemu lub w innych, rzadszych przypadkach. Teraz, w typowych przypadkach, logika parsowania używa ICU i bieżącej wartości zegara systemowego podczas analizowania nazw stref czasowych. Ta zmiana zapewnia bardziej poprawne wyniki, które mogą różnić się od wcześniejszych wersji Androida, gdy aplikacja używa klas takich jak SimpleDateFormat. Android O aktualizuje wersję ICU do wersji 58.

+0

Zasadniczo chcę mieć poprawną wartość WEEK_OF_YEAR, zależną od pierwszego dnia tygodnia, we wszystkich wersjach systemu Android. Mam aplikację timehseet i bardzo często używam gregorianCalendar, więc nie mam zamiaru przełączać się na inną klasę/lib. –

-1

Z tego, co myślę, problem leży w wierszu, w którym ustawiasz miesiąc.

// Tu w miesiącu Parametr, który podajesz 0, jest wartością, która może być przyczyną problemu, ponieważ pomimo tego, że tablica zaczyna się od 0 danych wejściowych, które akceptuje ten Calendar.MONTH, zawiera się między 1 a 12. Spróbuj zmienić to .

lub można również zmienić to na ustawienie go do stycznia jak stosowanie miesięcy

test.set(Calendar.MONTH, Calendar.JANUARY); 

// tutaj również w tej linii spróbować zmienić

test.setFirstDayOfWeek(Calendar.SUNDAY);//Set it to Sunday 

To powinno rozwiązać swoje problem.

+1

Przykro mi, kolego, to nieprawda. Wartość 'Calendar.JANUARY' jest również 0. –

+0

Jedynym powodem, dla którego mówię, aby użyć Calendar.JANUARY jest to, że jeśli przyjmiemy, że wartość JANUARY zmienia się z 0 na inną wartość, to twój kod nie będzie potrzebny do aktualizacji. –