2017-01-26 20 views
11

以下のコードは、NougatとPre-Nougatの結果が異なります。あなたが望むなら、見てみてください。なぜ誰かが私に説明して解決策を教えてもらえれば嬉しいです。GregorianCalendar setFirstDayOfWeekは、Nougat前のWEEK_OF_YEARには影響しません。

Androidのすべてのバージョンで、週の最初の曜日に応じて、正しいWEEK_OF_YEAR値が必要です。私はタイムシートアプリを持っているし、私はgregorianCalendarをたくさん使っているので、別のクラス/ libに切り替える気がしない。あなたはrelease notes for Nougatを見れば

//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

清算していただきありがとうございます。私の答えは、問題の方向に一般的な頷け(Nougatと一致するアプリとシステムのロケール)を除いて、今あなたにとって有用であるとは思わない。より良い回答を得るために、おそらくもっと何かを明確にすることができます。あなたのサンプルコードのロケールを設定して問題を再現するのか、それともあなたのアプリ内で何かしたいのですか?とにかくありがとう。 –

+0

ロケールは問題を再現するだけです。 –

答えて

3

あなたはロケールのサポートが強化されていることがわかります。

特に、アンドロイド7.0以前

、Androidは常に成功したアプリやシステムのロケールと一致していませんでした。

私は自分のデバイスでこれも気づいています。私の電話は英語(オーストラリア)ロケールで設定されています。ヌガー前に、

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

29 Janを印刷することになる(NO完全停止/期間)が、ヌガー後には(ピリオド)29 Jan.を印刷します。

具体的な内容を伝えるのは難しいですが、これがあなたのケースで起こっているようです。ポストノーガットを使用すると、ロケールの週の最初の曜日を含めて、アプリとシステムのロケールをよりよく一致させることができます。いずれにしても、ソースコードで公開されているJavaクラスではなく、libcoreの内部でコールが処理されるため、デバッガをステップ実行して原因を突き止めることはできません。 Androidデバイスが誤っ年の年/最初の週の最初の日を報告している場合、あなたはそれを回避する以外に行うことができますほとんどないだろう

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

あなたはまた、おそらく(​​を使用して試みることができますSDK 24で追加)を使用して問題を解決します。

Joda-timeのようなクラスを使用するか、新しいJSR-310クラス(ThreeTenバックポートを使用)を使用すると、GregorianCalendarを回避することなく、希望を得ることができます。一般に、これらのクラスは使いやすく、バグが発生しにくいクラスです。このような問題のため、多くの開発者は既にjava.util.Calendarjava.util.Dateをあきらめています。 to this canonical question詳細については

LocalDate.fromCalendarFields(test)を使用して、GregorianCalendarオブジェクトをLocalDateに変換することができます。これらのクラスはISO標準を使用しており、週の最初の曜日は常に月曜日です。次に、必要なロジックを上に書いてください。 GregorianCalendarの問題は、特定のロケールの年の最初の週を検索する単なる問題に「分離」されます。アプリにサーバーへの呼び出しが組み込まれている場合は、代わりにAPI呼び出しから週の最初の日にサービスを提供することができます。

更新:

注タイムゾーンの動作はAndroid Oに更新されました:

タイムゾーン名の解析が変更されている次のように

追加のロケールと国際化関連の変更です。以前は、Androidデバイスは、起動時にサンプリングされたシステムクロック値を使用して、日付時刻の解析に使用されたタイムゾーン名をキャッシュしていました。その結果、ブート時にシステムクロックが間違っていたり、まれに他のケースでシステムクロックが誤っていると、解析が悪影響を受ける可能性があります。 一般的に、解析ロジックは、タイムゾーン名を解析するときに、ICUと現在のシステムクロック値を使用します。この変更により、より正確な結果が得られます。これは、アプリがSimpleDateFormatのようなクラスを使用する場合、以前のAndroidバージョンとは異なる場合があります。 Android OはICUのバージョンをバージョン58に更新します。

+0

基本的には、Androidのすべてのバージョンで、週の最初の曜日に応じて正しいWEEK_OF_YEAR値が必要です。私はtimehseetアプリを持っており、私はgregorianCalendarをたくさん使っているので、別のクラス/ libに切り替える気がしません。 –

-1

あなたが月を設定している行に問題があると思います。

//この月のパラメータここでは、配列が0から始まっても、このCalendar.MONTHが受け入れる入力が1から12の間であるため、問題を作成する可能性のある値として0を渡しています。 。

か、また、月の使用として1月にそれを設定するために、このにそれを変更することができます

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

//また、ここでは、この行で試してみて、これが解決すべき

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

に変更するあなたの問題。

+1

申し訳ありませんが、これは当てはまりません。 'Calendar.JANUARY'の値も0です。 –

+0

Calendar.JANUARYの使用を唯一の理由は、JANUARYの値が0から別の値に変わったとすると、コードを更新する必要はありません。 –

関連する問題