Skip to content

Commit 5bbd26f

Browse files
authored
TimePicker formatting and parsing (#1207)
Superceeds #1060 Cleaned up the way the time picker displays and parses time strings. The behavior can be customized by changing the Language (to set culture information), Is24Hour, and WithSeconds properties.
1 parent 8444346 commit 5bbd26f

File tree

7 files changed

+331
-90
lines changed

7 files changed

+331
-90
lines changed

MaterialDesignThemes.Wpf.Tests/MaterialDesignThemes.Wpf.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<Compile Include="PaletteHelperFixture.cs" />
5252
<Compile Include="PopupBoxTests.cs" />
5353
<Compile Include="Properties\AssemblyInfo.cs" />
54+
<Compile Include="TimePickerUnitTests.cs" />
5455
<Compile Include="VisualTreeHelper.cs" />
5556
</ItemGroup>
5657
<ItemGroup>
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Windows;
5+
using System.Windows.Controls;
6+
using System.Windows.Markup;
7+
using Xunit;
8+
9+
namespace MaterialDesignThemes.Wpf.Tests
10+
{
11+
public class TimePickerUnitTests
12+
{
13+
private readonly TimePicker _timePicker;
14+
15+
public TimePickerUnitTests()
16+
{
17+
_timePicker = new TimePicker();
18+
_timePicker.ApplyDefaultStyle();
19+
}
20+
21+
[StaTheory]
22+
[MemberData(nameof(GetDisplaysExpectedTextData))]
23+
public void DisplaysExpectedText(CultureInfo culture, DatePickerFormat format, bool is24Hour, bool withSeconds,
24+
DateTime? selectedTime, string expectedText)
25+
{
26+
_timePicker.Language = XmlLanguage.GetLanguage(culture.IetfLanguageTag);
27+
_timePicker.SelectedTimeFormat = format;
28+
_timePicker.Is24Hours = is24Hour;
29+
_timePicker.WithSeconds = withSeconds;
30+
_timePicker.SelectedTime = selectedTime;
31+
32+
33+
string currentTestString = $"{culture.ThreeLetterISOLanguageName} {(is24Hour ? "24 Hour" : "12 Hour")} {format} format {(withSeconds ? "with seconds" : "")}";
34+
Assert.True(expectedText == _timePicker.Text, $"Expected '{expectedText}' but was '{_timePicker.Text}' - {currentTestString}");
35+
}
36+
37+
[StaTheory]
38+
[MemberData(nameof(GetParseLocalizedTimeStringData))]
39+
public void CanParseLocalizedTimeString(CultureInfo culture, DatePickerFormat format, bool is24Hour, bool withSeconds,
40+
string timeString, DateTime? expectedTime)
41+
{
42+
_timePicker.Language = XmlLanguage.GetLanguage(culture.IetfLanguageTag);
43+
_timePicker.SelectedTimeFormat = format;
44+
_timePicker.Is24Hours = is24Hour;
45+
_timePicker.WithSeconds = withSeconds;
46+
47+
var textBox = _timePicker.FindVisualChild<TextBox>(TimePicker.TextBoxPartName);
48+
textBox.Text = timeString;
49+
textBox.RaiseEvent(new RoutedEventArgs(UIElement.LostFocusEvent));
50+
51+
string currentTestString = $"{culture.ThreeLetterISOLanguageName} {(is24Hour ? "24 Hour" : "12 Hour")} {format} format {(withSeconds ? "with seconds" : "")}";
52+
Assert.True(expectedTime == _timePicker.SelectedTime, $"Expected '{expectedTime}' but was '{_timePicker.SelectedTime}' - {currentTestString}");
53+
}
54+
55+
public static IEnumerable<object[]> GetParseLocalizedTimeStringData()
56+
{
57+
//for now just using the same set of data to make sure we can go both directions.
58+
foreach (object[] data in GetDisplaysExpectedTextData())
59+
{
60+
var culture = (CultureInfo) data[0];
61+
bool is24Hour = (bool) data[2];
62+
var withSeconds = (bool) data[3];
63+
var date = (DateTime) data[4];
64+
var timeString = (string) data[5];
65+
66+
//Convert the date to Today
67+
date = DateTime.Today.AddHours(date.Hour).AddMinutes(date.Minute).AddSeconds(withSeconds ? date.Second : 0);
68+
69+
if (!is24Hour && date.Hour > 12 &&
70+
(string.IsNullOrEmpty(culture.DateTimeFormat.AMDesignator) ||
71+
string.IsNullOrEmpty(culture.DateTimeFormat.PMDesignator)))
72+
{
73+
//Because there is no AM/PM designator, 12 hour times will be treated as AM
74+
date = date.AddHours(-12);
75+
}
76+
77+
//Invert the order of the parameters.
78+
data[5] = date;
79+
data[4] = timeString;
80+
81+
82+
yield return data;
83+
}
84+
}
85+
86+
public static IEnumerable<object[]> GetDisplaysExpectedTextData()
87+
{
88+
//AM intentionally picks values with only a single digit to verify the DatePickerFormat is applied
89+
var am = new DateTime(2000, 1, 1, 3, 5, 9);
90+
//PM intentionally picks two digit values greater than 12 to ensure the 24 hour format is applied
91+
var pm = new DateTime(2000, 1, 1, 16, 30, 25);
92+
93+
//Invariant culture
94+
foreach (var data in GetDisplaysExpectedTextDataForCulture(CultureInfo.InvariantCulture, am,
95+
"3:05 AM", "3:05:09 AM", //12 hour short
96+
"03:05 AM", "03:05:09 AM", //12 hour long
97+
"3:05", "3:05:09", //24 hour short
98+
"03:05", "03:05:09")) //24 hour long
99+
{
100+
yield return data;
101+
}
102+
foreach (var data in GetDisplaysExpectedTextDataForCulture(CultureInfo.InvariantCulture, pm,
103+
"4:30 PM", "4:30:25 PM", //12 hour short
104+
"04:30 PM", "04:30:25 PM", //12 hour long
105+
"16:30", "16:30:25", //24 hour short
106+
"16:30", "16:30:25")) //24 hour long
107+
{
108+
yield return data;
109+
}
110+
111+
//US English
112+
var usEnglish = CultureInfo.GetCultureInfo("en-US");
113+
foreach (var data in GetDisplaysExpectedTextDataForCulture(usEnglish, am,
114+
"3:05 AM", "3:05:09 AM", //12 hour short
115+
"03:05 AM", "03:05:09 AM", //12 hour long
116+
"3:05", "3:05:09", //24 hour short
117+
"03:05", "03:05:09")) //24 hour long
118+
{
119+
yield return data;
120+
}
121+
foreach (var data in GetDisplaysExpectedTextDataForCulture(usEnglish, pm,
122+
"4:30 PM", "4:30:25 PM", //12 hour short
123+
"04:30 PM", "04:30:25 PM", //12 hour long
124+
"16:30", "16:30:25", //24 hour short
125+
"16:30", "16:30:25")) //24 hour long
126+
{
127+
yield return data;
128+
}
129+
130+
//Spain Spanish
131+
var spainSpanish = CultureInfo.GetCultureInfo("es-ES");
132+
foreach (var data in GetDisplaysExpectedTextDataForCulture(spainSpanish, am,
133+
"3:05", "3:05:09", //12 hour short
134+
"03:05", "03:05:09", //12 hour long
135+
"3:05", "3:05:09", //24 hour short
136+
"03:05", "03:05:09")) //24 hour long
137+
{
138+
yield return data;
139+
}
140+
foreach (var data in GetDisplaysExpectedTextDataForCulture(spainSpanish, pm,
141+
"4:30", "4:30:25", //12 hour short
142+
"04:30", "04:30:25", //12 hour long
143+
"16:30", "16:30:25", //24 hour short
144+
"16:30", "16:30:25")) //24 hour long
145+
{
146+
yield return data;
147+
}
148+
149+
//Iran Farsi fa-IR
150+
var iranFarsi = CultureInfo.GetCultureInfo("fa-IR");
151+
foreach (var data in GetDisplaysExpectedTextDataForCulture(iranFarsi, am,
152+
"3:05 ق.ظ", "3:05:09 ق.ظ", //12 hour short
153+
"03:05 ق.ظ", "03:05:09 ق.ظ", //12 hour long
154+
"3:05", "3:05:09", //24 hour short
155+
"03:05", "03:05:09")) //24 hour long
156+
{
157+
yield return data;
158+
}
159+
foreach (var data in GetDisplaysExpectedTextDataForCulture(iranFarsi, pm,
160+
"4:30 ب.ظ", "4:30:25 ب.ظ", //12 hour short
161+
"04:30 ب.ظ", "04:30:25 ب.ظ", //12 hour long
162+
"16:30", "16:30:25", //24 hour short
163+
"16:30", "16:30:25")) //24 hour long
164+
{
165+
yield return data;
166+
}
167+
}
168+
169+
private static IEnumerable<object[]> GetDisplaysExpectedTextDataForCulture(CultureInfo culture,
170+
DateTime dateTime,
171+
string short12Hour, string short12HourWithSeconds,
172+
string long12Hour, string long12HourWithSeconds,
173+
string short24Hour, string short24HourWithSeconds,
174+
string long24Hour, string long24HourWithSeconds)
175+
{
176+
yield return new object[]
177+
{
178+
culture,
179+
DatePickerFormat.Short,
180+
false,
181+
false,
182+
dateTime,
183+
short12Hour
184+
};
185+
yield return new object[]
186+
{
187+
culture,
188+
DatePickerFormat.Short,
189+
false,
190+
true,
191+
dateTime,
192+
short12HourWithSeconds
193+
};
194+
yield return new object[]
195+
{
196+
culture,
197+
DatePickerFormat.Long,
198+
false,
199+
false,
200+
dateTime,
201+
long12Hour
202+
};
203+
yield return new object[]
204+
{
205+
culture,
206+
DatePickerFormat.Long,
207+
false,
208+
true,
209+
dateTime,
210+
long12HourWithSeconds
211+
};
212+
yield return new object[]
213+
{
214+
culture,
215+
DatePickerFormat.Short,
216+
true,
217+
false,
218+
dateTime,
219+
short24Hour
220+
};
221+
yield return new object[]
222+
{
223+
culture,
224+
DatePickerFormat.Short,
225+
true,
226+
true,
227+
dateTime,
228+
short24HourWithSeconds
229+
};
230+
yield return new object[]
231+
{
232+
culture,
233+
DatePickerFormat.Long,
234+
true,
235+
false,
236+
dateTime,
237+
long24Hour
238+
};
239+
yield return new object[]
240+
{
241+
culture,
242+
DatePickerFormat.Long,
243+
true,
244+
true,
245+
dateTime,
246+
long24HourWithSeconds
247+
};
248+
}
249+
}
250+
}

MaterialDesignThemes.Wpf.Tests/VisualTreeHelper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using System.Reflection;
56
using System.Windows;
67

78
using WPFVisualTreeHelper= System.Windows.Media.VisualTreeHelper;

0 commit comments

Comments
 (0)