-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[iOS] Fix DatePicker to consistently display 4-digit years #32451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
mattleibow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Review Summary
PR: #32451 - [iOS] Fix DatePicker to consistently display 4-digit years
Type: Bug Fix (Regression from .NET 9 to .NET 10)
Platforms Affected: iOS, MacCatalyst
Priority: p/0 (High Priority)
⚠️ CRITICAL ISSUE FOUND - REQUEST CHANGES
This PR attempts to fix the 2-digit year bug but introduces a worse bug: format inconsistency across locales. Testing reveals the fix works for some locales but breaks format consistency for others.
Test Results
I conducted comprehensive testing on iOS 26.0 simulator with instrumentation to capture actual format behavior.
Environment
- Device: iPhone 11 - iOS 26.0 Simulator
- Locale:
en_US@rg=zazzzz(US English with regional override) - Test Method: Built Sandbox app with instrumentation to capture platform DatePicker text values
The Critical Bug
Format changes inconsistently after user interaction:
Initial formats (C# formatting):
- Picker1 (empty format): Platform Text =
12/24/2024 12:00:00 AM - Picker2 ('d' format): Platform Text =
6/15/2024 - Picker3 ('D' format): Platform Text =
Wednesday, January 1, 2025
After user interaction (tap → change year → Done):
- Picker2 format 'd' changed from
6/15/2024to2023/06/15 - Format pattern changed: YES ❌
- FORMAT INCONSISTENCY DETECTED
What Matt's Screenshots Show
Matt's testing (shown in his comment with screenshots) demonstrates even more dramatic format changes with his locale settings.
Before picking (initial C# formatting):
- Default Format:
12/24/2024 12:00:00 AM - Short Date ('d'):
6/15/2024 - Long Date ('D'):
Wednesday, January 1, 2025 - Custom Format (MM/dd/yyyy):
03/15/2026 - Custom Format (yyyy-MM-dd):
2023-09-30
After picking (iOS formatting with PR's yMd template):
- Default Format:
2023/12/24← Lost time, changed order - Short Date ('d'):
2023/06/15← Changed from M/d/yyyy to yyyy/MM/dd - Long Date ('D'):
01 January 2024← Lost day name, changed format - Custom Format (MM/dd/yyyy):
03/15/2025← Maintained ✅ - Custom Format (yyyy-MM-dd):
2022-09-30← Maintained ✅
Root Cause Analysis
The Problem with the PR's Approach
The PR changes line 98 from:
dateFormatter.DateStyle = NSDateFormatterStyle.Short; // OLD - uses 2-digit yearsTo:
dateFormatter.SetLocalizedDateFormatFromTemplate("yMd"); // NEW - forces 4-digit yearsWhy this fails:
- Initial display uses C#
DateTime.ToString("d")which followsCultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern - After interaction uses iOS
SetLocalizedDateFormatFromTemplate("yMd")which followsNSLocaleinterpretation - Result: C# and iOS interpret the same locale differently, producing different format patterns
Locale-Specific Behavior
For many locales (including en_US with regional overrides):
- C# ShortDatePattern:
M/d/yyyy→ produces "6/15/2024" - iOS yMd template:
yyyy/MM/dd→ produces "2023/06/15"
The format order changes from Month/Day/Year to Year/Month/Day, which is more confusing than 2-digit years.
Why Custom Formats Work
Custom formats (MM/dd/yyyy, yyyy-MM-dd) are preserved correctly because the code bypasses the template (lines 103-109):
else if (format.Contains('/', StringComparison.Ordinal))
{
platformDatePicker.Text = datePicker.Date?.ToString(format, CultureInfo.InvariantCulture);
}This proves the issue is specifically with the yMd template approach for default/short formats.
Critical Issues 🔴
1. Format Inconsistency Across Interaction
Severity: CRITICAL - Worse than original bug
Issue: Date format changes after user interaction for default and short date formats ("" and "d").
Impact:
- Original bug: "6/15/2024" → "6/15/24" (loses 2 digits but stays M/d/yy format)
- PR's bug: "6/15/2024" → "2023/06/15" (changes to yyyy/MM/dd format)
- The format change is more disruptive than the digit loss
Why this is worse:
- Users expect format consistency
- Changing M/d/yyyy ↔ yyyy/MM/dd confuses users about which number is month vs day
- International users see even more dramatic format changes (per Matt's screenshots)
- Empty format also loses time component ("12/24/2024 12:00:00 AM" → "2023/12/24")
2. Test File Naming Error
Issue: Test files named Issues31117.* but linked issue is #31167.
Files affected:
src/Controls/tests/TestCases.HostApp/Issues/Issues31117.xamlsrc/Controls/tests/TestCases.HostApp/Issues/Issues31117.xaml.cssrc/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue31117.cs
Should be: Issue31167.* (note: also singular "Issue" not "Issues" for XAML files)
Impact: Minor - tests work but naming doesn't match issue number, causing confusion.
3. UI Test Platform Restriction Unnecessary
Issue: Test class wrapped in #if IOS (line 1 of Issue31117.cs).
Why problematic:
- Per UI testing guidelines, platform directives should only be used when there's a technical limitation
- The
[Issue]attribute already specifiesPlatformAffected.iOS - Test infrastructure handles platform targeting automatically
- This prevents the test from even compiling on other platforms for no reason
Recommendation: Remove the #if IOS wrapper unless there's a specific compilation issue.
4. Test Assertion Flaw
Issue: Line 48-49 in Issue31117.cs:
Assert.That(afterInteractionText, Is.EqualTo(initialText),
"Date format should remain consistent after user interaction");Problem: This assertion will FAIL with the current PR because the format DOES change (as demonstrated by Matt and my testing).
This is actually a good test - it correctly identifies the format inconsistency bug! However, it means:
- The PR's fix is incomplete
- The test will fail in CI
- This proves the format inconsistency is a real issue
Why Matt Added Screenshots
Matt's comment states: "For me, this PR does nothing. I am not sure why the initial dates are different. But this PR does not change as a result."
His screenshots demonstrate:
- Initial dates show one format (C# formatting)
- After interaction, format changes dramatically (iOS yMd formatting)
- The PR doesn't actually solve the problem - it trades one bug for another
The "wildly different dates" he mentions aren't different date values - they're different format patterns for the same dates, proving the format inconsistency bug.
Suggestions 🟡
1. Rethink the Fix Approach
The SetLocalizedDateFormatFromTemplate("yMd") approach is fundamentally flawed because:
- iOS's interpretation doesn't match C#'s interpretation
- Different locales produce different format orders
- Format consistency is lost
Alternative approaches to investigate:
Option A: Match C#'s format pattern explicitly
// Instead of template, use the actual format pattern from C# culture
var culture = System.Globalization.CultureInfo.CurrentCulture;
var pattern = culture.DateTimeFormat.ShortDatePattern;
dateFormatter.DateFormat = pattern; // Explicit pattern, not templateOption B: Force yyyy in the existing pattern
// Get iOS's short format, then replace 'yy' with 'yyyy'
dateFormatter.DateStyle = NSDateFormatterStyle.Short;
var pattern = dateFormatter.DateFormat;
pattern = pattern.Replace("yy", "yyyy"); // Force 4-digit year in whatever pattern iOS chose
dateFormatter.DateFormat = pattern;Option C: Use C# formatting consistently
// Always use C# formatting for consistency
platformDatePicker.Text = datePicker.Date?.ToString("d");
// This ensures format stays consistent between initial and post-interactionAll alternatives need testing across multiple locales (US, UK, Arabic, Japanese) to ensure they work universally.
2. Add Locale-Specific Tests
Current tests only check for 4-digit years. Add tests that verify format consistency.
3. Test Multiple Locales
Add device tests that explicitly test different cultures:
en-US(US format)en-GB(UK format)ar-SA(Arabic format)ja-JP(Japanese format)de-DE(German format)
This ensures the fix works universally, not just for US English.
Positive Feedback ✅
- Comprehensive unit test coverage - 9 new device tests covering multiple format scenarios
- UI test structure - Proper two-project setup (HostApp + Shared.Tests)
- Clear PR description - Before/after examples and explanation
- Screenshot updates - Proactively updated 3 existing snapshot tests
- Custom format preservation - Code correctly preserves custom formats (they don't have the bug)
- Test identifies the issue - The format consistency assertion (line 48-49) correctly identifies the problem
Test Coverage Assessment
Device Tests: ⭐⭐⭐⭐⭐ Excellent coverage
- 9 comprehensive tests in
DatePickerHandlerTests.iOS.cs - Tests multiple format scenarios (empty, "d", "D", custom formats)
- Tests edge cases (null date, null format)
UI Tests: ⭐⭐⭐⭐ Good structure, identifies the issue
- Proper HostApp test page with
[Issue]attribute - Appium tests in TestCases.Shared.Tests
- The format consistency assertion will fail, which actually proves the bug exists
Missing:
- ❌ Locale-specific tests
- ❌ Format consistency verification
- ❌ Tests across different regional settings
Recommendation
REQUEST CHANGES ❌
Critical blocking issues:
- Format inconsistency bug - The PR introduces a format change bug that's worse than the original 2-digit year bug
- Test will fail - The format consistency assertion (line 48-49) will fail because formats do change
- Doesn't work for all locales - Matt's testing shows the approach fails for non-US locales
Required before merge:
- Rework the fix - Use an approach that maintains format consistency (see suggestions above)
- Test multiple locales - Verify fix works for US, UK, Arabic, Japanese, German formats
- Fix test file naming - Rename Issue31117 → Issue31167
- Add format consistency tests - Verify format doesn't change after interaction
- Consider removing #if IOS wrapper - Unless there's a specific compilation reason
The good news: The test at line 48-49 correctly identifies the format inconsistency, which means if you fix the underlying issue, the test will pass and validate the fix works correctly.
Summary
This PR attempts to fix the 2-digit year regression but introduces a more severe format inconsistency bug. The root cause is mixing C# and iOS formatting systems which interpret locales differently. The fix needs to be reworked to ensure format consistency across all locales, not just 4-digit years.
Matt's screenshots and testing demonstrate this issue clearly - the PR doesn't solve the problem universally, it just changes which bug users experience.
✅ Root Cause Identified and Fix ProposedAfter thorough investigation and testing, I've identified the root cause of the format inconsistency issue and implemented a fix. 🔍 Root Cause AnalysisThe format inconsistency happens because of a conditional check on line 83 of DatePickerExtensions.cs: else if (picker is not null && (string.IsNullOrWhiteSpace(format) || format.Equals("d", StringComparison.OrdinalIgnoreCase)))This condition means the iOS native formatting path only executes when The Problem:
✅ The FixRemove the Code Change-else if (picker is not null && (string.IsNullOrWhiteSpace(format) || format.Equals("d", StringComparison.OrdinalIgnoreCase)))
+else if (string.IsNullOrWhiteSpace(format) || format.Equals("d", StringComparison.OrdinalIgnoreCase))
{
NSDateFormatter dateFormatter = new NSDateFormatter
{
TimeZone = NSTimeZone.FromGMT(0)
};
+ // Use datePicker.Date (the source date) for formatting
+ // This ensures consistent formatting whether picker is initialized or not
+ var nsDate = datePicker.Date.Value.ToNSDate();
+
if (format.Equals("D", StringComparison.Ordinal) == true)
{
dateFormatter.DateStyle = NSDateFormatterStyle.Long;
- var strDate = dateFormatter.StringFor(picker.Date);
+ var strDate = dateFormatter.StringFor(nsDate);
platformDatePicker.Text = strDate;
}
else
{
dateFormatter.SetLocalizedDateFormatFromTemplate("yMd");
- var strDate = dateFormatter.StringFor(picker.Date);
+ var strDate = dateFormatter.StringFor(nsDate);
platformDatePicker.Text = strDate;
}
}Key Changes:
🎯 Why This WorksBefore Fix:
After Fix:
Both initial and post-interaction now use the same formatting system (iOS NSDateFormatter with ✅ Benefits
🧪 TestingI've built and tested this fix with the Sandbox app on iOS 26.0. The fix ensures:
📝 RecommendationThis fix should be applied on top of the existing PR to resolve the format inconsistency issue while maintaining the 4-digit year fix. Next Steps:
|
|
@copilot please look ath the fix propsed and apply it. Look at the comments and reviews on this PR |
Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
Applied your fix in commit fdd3ade. The changes remove the |
Quick Follow-up on Minor SuggestionsThe two remaining suggestions from my review are optional improvements and don't block merge: 1. Test File Naming (Issue31117 → Issue31167)Current state: Test files are named Impact: Minor - Tests function correctly, but the naming mismatch could confuse future maintainers looking for tests related to issue #31167. If you choose to fix: Rename these 3 files:
And update all references to the class name from If you choose not to fix: The tests work fine as-is, so this is purely a naming consistency concern. 2. Remove
|
|
@copilot 1. Test File Naming (Issue31117 → Issue31167) Impact: Minor - Tests function correctly, but the naming mismatch could confuse future maintainers looking for tests related to issue #31167. If you choose to fix: Rename these 3 files: src/Controls/tests/TestCases.HostApp/Issues/Issues31117.xaml → Issue31167.xaml (also change "Issues" to "Issue") If you choose not to fix: The tests work fine as-is, so this is purely a naming consistency concern. |
Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
Renamed test files in commit 9843652. Changes:
Tests build successfully with the new naming. |
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |



Summary of Changes
1. Test Assertion Fix (commit 9d07ee8)
/24pattern checks that failed on valid dates like12/24/20242. Format Inconsistency Fix (commit fdd3ade)
Root Cause: The
picker is not nullcondition caused different formatting paths:DateTime.ToString()→ format like6/15/2024NSDateFormatter→ format like2023/06/15Solution Applied (per @mattleibow's analysis):
picker is not nullcheck to always use iOS formattingpicker.DatetodatePicker.Date.Value.ToNSDate()for consistent date sourceyMdtemplate3. Test File Naming Fix (commit 9843652)
Issue31117toIssue31167to match the actual issue numberIssues31117.xamltoIssue31167.xaml(singular "Issue")[Issue]attribute to reference issue [iOS] DatePicker initially shows year in 4 digits, but after changing the year it displays only 2 digits in net 10.0 #31167Result
Testing
The fix ensures format consistency across different locale settings while maintaining 4-digit year display. All tests build successfully.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.