次のStack Overflowのやりとりが答えの全て。
Intent.ACTION_DATE_CHANGED
はリファレンスによると日付が変わった時(つまり毎日0時0分)に飛んでくるブロードキャストインテントらしいのだが、時刻を求める処理にバグがあって、夜中ではなく正午に飛んでくることがある。
このインテントを発行しているのはAlarmManagerService
という内部のクラス。端末起動時のインスタンスのセットアップで「次の日の0時」を計算してアラームをセットする。
問題の箇所は前述のStack Overflowの回答にもあるように、Calendar
インスタンスを使って「今の時刻の時間と分と秒とミリ秒を0にして日付に1足す」ところで、時間を午前か午後の0時としてしまっているところ。このコードを注釈なしでどこが間違っているかパッとわかればおそらくJava初段くらいのウデマエと言ったところではないだろうか。僕は4級ぐらいなのでわからなかった。
public void scheduleDateChangedEvent() { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR, 0); // !!! 正しくは Calendar.HOUR_OF_DAY とすべき calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.DAY_OF_MONTH, 1); final WorkSource workSource = null; // Let system take blame for date change events. setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, AlarmManager.FLAG_STANDALONE, workSource, null, Process.myUid()); }
つまり、端末を起動したのが午前中なら正しく夜の0時にインテントが飛んでくるはずだが、端末を起動したのが午後だとインテントは正午に飛んできてしまうということである。
Issue Trackerには2009年に報告されており、それからAndroid 6.0までずっと放置されている模様。
どうしても日付が変わった時に何かしたいときは、 Intent.ACTION_DATE_CHANGED
を受けた時に正午だったら12時間後にオリジナルなインテントを発行するアラームをセットするなどの対策が必要。
「深夜0時に何か起きててアプリが動かない」というような相談を受けていろいろ調べた時に見つけたネタ。ちなみに相談とは全然関係なかった。