{"data":{"id":"magento2-39690","source":"github-pr","sourceRef":"magento/magento2#39690","title":"Special Price To Date is wrongly validated on applySpecialPrice ","pr":{"number":39690,"url":"https://github.com/magento/magento2/pull/39690","author":"KrasnoshchokBohdan","mergedAt":"2025-07-02T13:10:14Z","mergeCommit":"c75187542b567bb1f3c3f23c1f0ed5005c78f811","headCommit":"bd6ef727bea8e531ba26aad079c03fefad48e949","baseRef":"2.4-develop","diffSha256":"c3c5db60b8f00c592b9b6e7f41c48b199380f6c4556ed5113a62279e7a8e49c5"},"issues":[{"number":39169,"url":"https://github.com/magento/magento2/issues/39169","title":"Special Price To Date is wrongly validated on applySpecialPrice ","labels":["Area: APIs","Component: Api","Issue: Confirmed","Priority: P3","Progress: done","Reported on 2.4.4-p7","Reproduced on 2.4.x"],"kind":"human"}],"fixedIn":"2.4.9","containingTags":["2.4.9"],"reportedOn":"2.4.4-p7","codeMatch":{"2.4.6":"conflict","2.4.6-p1":"conflict","2.4.6-p2":"conflict","2.4.6-p3":"conflict","2.4.6-p4":"conflict","2.4.6-p5":"conflict","2.4.6-p6":"conflict","2.4.6-p7":"conflict","2.4.6-p8":"conflict","2.4.6-p9":"conflict","2.4.6-p10":"conflict","2.4.6-p11":"conflict","2.4.6-p12":"conflict","2.4.6-p13":"conflict","2.4.6-p14":"conflict","2.4.6-p15":"conflict","2.4.7":"conflict","2.4.7-p1":"conflict","2.4.7-p2":"conflict","2.4.7-p3":"conflict","2.4.7-p4":"conflict","2.4.7-p5":"conflict","2.4.7-p6":"conflict","2.4.7-p7":"conflict","2.4.7-p8":"conflict","2.4.7-p9":"conflict","2.4.7-p10":"conflict","2.4.8":"clean","2.4.8-p1":"clean","2.4.8-p2":"clean","2.4.8-p3":"clean","2.4.8-p4":"clean","2.4.8-p5":"clean","2.4.9":"conflict"},"affectedVersions":["2.4.8","2.4.8-p1","2.4.8-p2","2.4.8-p3","2.4.8-p4","2.4.8-p5"],"components":["magento/framework","magento/module-bundle","magento/module-catalog"],"files":[{"path":"app/code/Magento/Bundle/Model/Product/Price.php","change":"modified","package":"magento/module-bundle"},{"path":"app/code/Magento/Catalog/Model/Pricing/SpecialPriceService.php","change":"added","package":"magento/module-catalog"},{"path":"app/code/Magento/Catalog/Model/Product/Type/Price.php","change":"modified","package":"magento/module-catalog"},{"path":"app/code/Magento/Catalog/Pricing/Price/SpecialPrice.php","change":"modified","package":"magento/module-catalog"},{"path":"lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php","change":"modified","package":"magento/framework"}],"stripped":{"tests":["app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php","app/code/Magento/Bundle/Test/Unit/Pricing/Price/SpecialPriceTest.php","app/code/Magento/Catalog/Test/Unit/Service/SpecialPriceServiceTest.php"],"docs":[],"outsideCode":[]},"linesChanged":97,"mergeBatched":false,"excluded":null,"sections":{"description":"End date is missed and expire day after","stepsToReproduce":"Use Rest API to set special price \n/rest/default/V1/products/special-price\n\nprovide body like \n```json\n{\n  \"prices\": [\n    {\n      \"price\": 5,\n      \"store_id\": 1,\n      \"sku\": \"1181\",\n      \"price_from\": \"2024-08-02 17:00:00\",\n      \"price_to\": \"2024-09-12 17:00:00\",\n      \"extension_attributes\": {}\n    }\n  ]\n}\n```\nthen check your price on front-end \nadmin or whatever\n\nyour special price will be visible until tomorrow 17\n\nso instead expire at 2024-09-12 17:00:00 it will expire on 2024-09-13 17:00:00\n\nbecause of validation on Magento\\Catalog\\Model\\Product\\Type\\Price::calculateSpecialPrice\n\n```php\n            if ($this->_localeDate->isScopeDateInInterval($store, $specialPriceFrom, $specialPriceTo)) {\n                $finalPrice = min($finalPrice, (float) $specialPrice);\n            }\n```\n\ninstead of check in range from -> to \nit add to end date 1 day \n\nMagento\\Framework\\Stdlib\\DateTime\\Timezone::isScopeDateInInterval\n\nmaybe it can be used for other validation but for real not for calculateSpecialPrice it should be in range from -> to set by admin","expectedResult":"Product special price should expire on date set by admin or 3rd party system by REST API","actualResult":"End date is missed and expire day after","source":"issue"},"signatures":[],"labels":{"area":["APIs"],"component":["Api"],"priority":"P3","severity":null,"reportedOn":["2.4.4-p7"]},"categories":[],"triage":{"model":"@cf/cloudflare/clef","requestHash":"e84867665169705d1eda32899c69fade5630c7bbdd82abc5b9737c747de0d29a","isBugfix":0.9737,"changeKind":{"choice":"bugfix","probabilities":{"bugfix":0.95,"feature":0.0076,"refactor":0.0249,"tests_only":0.0097,"docs_only":0.0036,"dependency":0.0042},"confidence":0.8839},"scope":{"score":1.479,"probabilities":{"0":0.1001,"1":0.3208,"2":0.5791},"confidence":0.1725},"risk":{"score":1.4797,"probabilities":{"0":0.1256,"1":0.2691,"2":0.6053},"confidence":0.1818},"area":{"choice":"catalog","probabilities":{"catalog":0.5105,"checkout":0.0424,"customer":0.0081,"admin":0.027,"graphql_api":0.1593,"framework":0.2105,"frontend":0.0159,"other":0.0263},"confidence":0.2386},"securityRelevant":0.0063,"reportedVersion":{"choice":"2.4.4-p7","probabilities":{"2.4.0":0.0019,"2.4.0-p1":0.0024,"2.4.1":0.0021,"2.4.1-p1":0.0025,"2.4.2":0.0026,"2.4.2-p1":0.0029,"2.4.2-p2":0.003,"2.4.3":0.003,"2.4.3-p1":0.003,"2.4.3-p2":0.0037,"2.4.3-p3":0.0033,"2.4.4":0.0426,"2.4.4-p1":0.0027,"2.4.4-p10":0.0046,"2.4.4-p11":0.0063,"2.4.4-p12":0.0035,"2.4.4-p13":0.0032,"2.4.4-p14":0.0036,"2.4.4-p15":0.0031,"2.4.4-p16":0.0029,"2.4.4-p17":0.0053,"2.4.4-p18":0.0034,"2.4.4-p2":0.0024,"2.4.4-p3":0.0027,"2.4.4-p4":0.0036,"2.4.4-p5":0.0038,"2.4.4-p6":0.01,"2.4.4-p7":0.5756,"2.4.4-p8":0.0059,"2.4.4-p9":0.0065,"2.4.5":0.0047,"2.4.5-p1":0.0055,"2.4.5-p10":0.0042,"2.4.5-p11":0.0052,"2.4.5-p12":0.0059,"2.4.5-p13":0.0052,"2.4.5-p14":0.0056,"2.4.5-p15":0.0047,"2.4.5-p16":0.0049,"2.4.5-p17":0.0052,"2.4.5-p2":0.003,"2.4.5-p3":0.0039,"2.4.5-p4":0.0039,"2.4.5-p5":0.004,"2.4.5-p6":0.0045,"2.4.5-p7":0.0049,"2.4.5-p8":0.0033,"2.4.5-p9":0.0027,"2.4.6":0.0059,"2.4.6-p1":0.0068,"2.4.6-p10":0.0052,"2.4.6-p11":0.0059,"2.4.6-p12":0.007,"2.4.6-p13":0.0051,"2.4.6-p14":0.0049,"2.4.6-p15":0.0046,"2.4.6-p2":0.004,"2.4.6-p3":0.0049,"2.4.6-p4":0.0051,"2.4.6-p5":0.0049,"2.4.6-p6":0.0059,"2.4.6-p7":0.0059,"2.4.6-p8":0.0042,"2.4.6-p9":0.0034,"2.4.7":0.0055,"2.4.7-p1":0.0053,"2.4.7-p10":0.0046,"2.4.7-p2":0.0041,"2.4.7-p3":0.0058,"2.4.7-p4":0.0068,"2.4.7-p5":0.0061,"2.4.7-p6":0.0077,"2.4.7-p7":0.0067,"2.4.7-p8":0.0048,"2.4.7-p9":0.0035,"2.4.8":0.006,"2.4.8-p1":0.0074,"2.4.8-p2":0.0072,"2.4.8-p3":0.0068,"2.4.8-p4":0.0082,"2.4.8-p5":0.007,"2.4.9":0.0055,"unspecified":0.0039},"confidence":0.327},"backportWorthy":{"score":1.3338,"probabilities":{"0":0.1215,"1":0.4233,"2":0.4552},"confidence":0.1018}},"curated":{"title":"Special price with a time in price_to is valid one day longer","description":"A special price with a price_to that has a time, like 2024-09-12 17:00:00, is visible one day longer, because isScopeDateInInterval adds one day to the end date. A new SpecialPriceService subtracts one day from the date when it contains a specific time other than 00:00:00, and the catalog Price, Bundle Price and SpecialPrice use it with isScopeDateInInterval.","categories":[],"author":"claude-code/opus-5.5","date":"2026-10-06","reviewedBy":null},"tests":{"2.4.8-p5":{"before":"not-runnable","after":"pass","adapted":false,"runAt":"2026-10-06T09:20:08.996Z","releaseCommit":"870a22c63d9d9b68fa3297962e2d5d5841115814","suites":{"unit":{"before":"not-runnable","after":"pass","runAt":"2026-10-06T09:20:08.996Z"}}}}},"_documentation":"https://magento.watch/api","_description":"Upstream fix magento2-39690 details"}