-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Open
Labels
needs triageThis issue needs to be triaged by the teamThis issue needs to be triaged by the team
Description
Is this a regression?
- Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
No response
Description
When using Angular’s timepicker with a shared FormControl, Luxon as the date adapter (with a fixed timezone and locale), there is an edge case when switching from DST → standard time.
The problem arises because _assignUserSelection
uses getValidDateOrNull
and then applies extracted hours/minutes/seconds onto a target date that may carry the wrong DST context. This causes the two distinct 02:00
times (DST vs standard) on the fallback day to collapse into one — selecting the non-DST 02:00
ends up mapped to the DST 02:00
.
Custom DateAdapter:
To ensure consistent Luxon DateTime
handling, I replaced the default LuxonDateAdapter
with a custom one.
@Injectable()
export class CustomDateAdapter extends LuxonDateAdapter {
protected override locale = DateTimeService.LOCALE;
constructor() {
super(DATE_FORMATS);
}
/** Ensure datepicker provides Luxon DateTimes in the default zone */
public override createDate(year: number, month: number, date: number): DateTime {
return super.createDate(year, month, date)
.setZone(DateTimeService.DEFAULT_ZONE)
.setLocale(DateTimeService.LOCALE);
}
/**
* Needed so the timepicker does not treat DST and non-DST versions of the same wall time as equal.
* Without this, both values are considered the same and the DST one always “wins”.
*/
public override sameTime(first: DateTime | null, second: DateTime | null): boolean {
if (!isDefined(first) || !isDefined(second)) {
return false;
}
return +first === +second;
}
public override clone(date: DateTime): DateTime {
let cloned = super.clone(date);
cloned = cloned.setZone(DateTimeService.DEFAULT_ZONE);
cloned = cloned.setLocale(DateTimeService.LOCALE);
return cloned;
}
}
´´´
Despite these adjustments, the underlying `_assignUserSelection` logic in the timepicker still collapses the two 02:00 times into one, because of how it uses the last valid date + setTime.
### Reproduction
StackBlitz link: https://stackblitz.com/edit/stackblitz-starters-fyaws5vk
Steps to reproduce:
* Use the custom CustomDateAdapter (above) instead of the default LuxonDateAdapter.
On the DST end day ( 2025-10-26), try selecting both 02:00 (DST) and 02:00 (STD).
* Observe that selecting the 02:00 (STD) still results in the 02:00 (DST) value being applied (or both depending on Custom vs LuxonDateAdapter).
### Expected Behavior
* The timepicker should treat 02:00 DST and 02:00 STD as distinct values when using a fixed timezone.
* Selecting the standard-time 02:00 should not be coerced into the DST-time 02:00.
### Actual Behavior
* Because `_assignUserSelection` rebuilds the target date and applies extracted hours, the ambiguous hour is resolved to the earlier offset (DST).
* Even with a custom adapter that distinguishes times (`sameTime` override), the timepicker ends up normalizing both selections to the DST instance.
### Environment
- Angular: 20.2
- CDK/Material: 20.2
- Browser(s): Chrome, ...
- Operating System (e.g. Windows, macOS, Ubuntu): macOS
- Custom DateAdapter: subclass of LuxonDateAdapter (see above)
- Timezone: Europe/Vienna
Metadata
Metadata
Assignees
Labels
needs triageThis issue needs to be triaged by the teamThis issue needs to be triaged by the team