While APNs tries to honor the expiration time for a push request, this may not always be possible. A single APNs attempt may involve retries over multiple network interfaces and connections of the destination device. Often these retries span over some time period, depending on the network characteristics. In addition, a push notification may take some time on the network after APNs sends it to the device. APNs uses best efforts to honor the expiry date without any guarantee.
In your case, the difference between using an ad-hoc build vs App Store build also changes the APNs endpoints you would be sending the request to, and also the endpoints the device is receiving the pushes from. It is possible that differences in the network paths between APNs development servers and your device could be having different timing profiles.
It is important to understand that setting the expiration time does not guarantee that no push will never be delivered past the set time. It is on a best-effort basis.
Also, please confirm that the push request contents are identical between the ones sent to the ad-hoc vs the App Store version. As your requests will be different at minimum for the endpoints, it would be a good idea to make sure the rest is identical.