Android 6 (API23) introduced Doze mode which interferes with AlarmManager. It uses certain maintenance windows to handle alarms, so even if you used setExactAndAllowWhileIdle() you cannot make sure that your alarm fires at the desired point of time.
You can turn this behavior off for your app using your phone's settings (Settings/General/Battery & power saving/Battery usage/Ignore optimizations or similar)
Inside your app you can check this setting ...
... and eventually show the respective settings dialog:
Creating exact alarms on all Android versions
With more and more battery optimizations being put into the Android system over time, the methods of the AlarmManager have also significantly changed (to allow for more lenient timing). However, for some applications it is still required to be as exact as possible on all Android versions. The following helper uses the most accurate method available on all platforms to schedule a PendingIntent:
How to Cancel an Alarm
If you want to cancel an alarm, and you don't have a reference to the original PendingIntent used to set the alarm, you need to recreate a PendingIntent exactly as it was when it was originally created.