feat(module: timepicker): add 12-hour time support (#2501)

* feat(module: datepicker): add 12-hour time support

* fix(module: datepicker): revert 24-hour time format

* fix(module: datepicker): AM/PM not localized in the date input component

* fix(module: datepicker): AM/PM in the selection panel are not localized

* Update components/date-picker/internal/DatePickerDatetimePanel.razor

Co-authored-by: James Yeung <shunjiey@hotmail.com>

* fix(module: datepicker). AM/PM switches toggling incorrectly

* fix(module: datepicker): 24-hour format in DatePicker when Use12Hours

* fix(module: datepicker): time format in docs

* refactor(module: datepicker): code cleanup

* feat(module: datepicker): add 12-hour format to en-US locale
This commit is contained in:
Alex Kryvdyk 2022-06-10 14:43:33 +03:00 committed by GitHub
parent 1659aef02d
commit acb6c892b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 45 deletions

View File

@ -271,6 +271,9 @@ namespace AntDesign
CurrentValue = DefaultValue;
else
CurrentValue = default;
PickerValues[0] = _pickerValuesAfterInit;
if (closeDropdown)
Close();
if (OnClearClick.HasDelegate)

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@ -125,7 +125,7 @@ namespace AntDesign
}
public bool IsShowTime { get; protected set; }
public string ShowTimeFormat { get; protected set; } = "HH:mm:ss";
public string ShowTimeFormat { get; protected set; }
protected OneOf<bool, string> _showTime = null;
private bool _timeFormatProvided;
@ -244,9 +244,12 @@ namespace AntDesign
[Parameter]
public Func<DateTime, RenderFragment> MonthCellRender { get; set; }
public DateTime CurrentDate { get; set; } = DateTime.Now;
[Parameter]
public bool Use12Hours { get; set; }
protected DateTime[] PickerValues { get; } = new DateTime[] { DateTime.Now, DateTime.Now };
public DateTime CurrentDate { get; set; } = DateTime.Today;
protected DateTime[] PickerValues { get; } = new DateTime[] { DateTime.Today, DateTime.Today };
public bool IsRange { get; set; }
@ -298,6 +301,11 @@ namespace AntDesign
{
_needRefresh = true;
if (!_timeFormatProvided || string.IsNullOrEmpty(ShowTimeFormat))
{
ShowTimeFormat = Use12Hours ? Locale.Lang.TimeFormat12Hour : Locale.Lang.TimeFormat;
}
return base.SetParametersAsync(parameters);
}
@ -658,6 +666,7 @@ namespace AntDesign
DatePickerType.Date => GetTimeFormat(),
DatePickerType.Month => Locale.Lang.YearMonthFormat,
DatePickerType.Year => Locale.Lang.YearFormat,
DatePickerType.Time when Use12Hours => Locale.Lang.TimeFormat12Hour,
DatePickerType.Time => Locale.Lang.TimeFormat,
DatePickerType.Week => $"{Locale.Lang.YearFormat}-0{Locale.Lang.Week}",
DatePickerType.Quarter => $"{Locale.Lang.YearFormat}-Q0",
@ -676,7 +685,7 @@ namespace AntDesign
{
return $"{Locale.Lang.DateFormat} {ShowTimeFormat}";
}
return Locale.Lang.DateTimeFormat;
return Use12Hours ? Locale.Lang.DateTimeFormat12Hour : Locale.Lang.DateTimeFormat;
}
return Locale.Lang.DateFormat;
}
@ -696,7 +705,7 @@ namespace AntDesign
};
else
format = InternalFormat;
return value.ToString(format, CultureInfo.InvariantCulture);
return value.ToString(format, CultureInfo.CurrentCulture);
}
/// <summary>

View File

@ -1,4 +1,4 @@
@namespace AntDesign.Internal
@namespace AntDesign.Internal
@typeparam TValue
@inherits DatePickerPanelBase<TValue>
@ -71,23 +71,25 @@
timeFormat = Format;
}
var use12Hours = Use12Hours || timeFormat.ToLower().Contains("t");
var isPM = use12Hours && Value?.Hour >= 12;
DatePickerDisabledTime disabledTime = GetDisabledTime();
bool isValueNull = Value is null;
Func<int, int?, string> selected;
string localValue;
if (Value is null)
{
localValue = "";
selected = (_, _) => "";
}
else
{
localValue = Value.Value.ToString(timeFormat);
selected = (viewTime, valueTime) => viewTime == valueTime ? $"{PrefixCls}-time-panel-cell-selected" : "";
}
bool isValueNull = Value is null;
Func<int, int?, string> selected;
string localValue;
if (Value is null)
{
localValue = "";
selected = (_, _) => "";
}
else
{
localValue = Value.Value.ToString(timeFormat);
selected = (viewTime, valueTime) => viewTime == valueTime ? $"{PrefixCls}-time-panel-cell-selected" : "";
}
}
<div class="@(PrefixCls)-time-panel">
@if(Picker == DatePickerType.Date)
@if (Picker == DatePickerType.Date)
{
<div class="@(PrefixCls)-header">
<div class="@(PrefixCls)-header-view">
@ -99,21 +101,31 @@
<div class="@(PrefixCls)-content">
@if (timeFormat.ToLower().Contains("hh"))
{
var selectFirstHour = Value is not null && disabledTime._disabledHours.Contains(Value.Value.Hour);
var hoursOffset = isPM ? 12 : 0;
<ul class="@(PrefixCls)-time-panel-column" style="position: relative;">
@for (int hour = 0; hour < 24; hour++)
@for (int hour = 0; hour < (use12Hours ? 12 : 24); hour++)
{
var viewTime = startTime;
bool disabled = disabledTime._disabledHours.Contains(hour);
string isSelectedCls = selected(viewTime.Hour, Value?.Hour);
bool disabled = disabledTime._disabledHours.Contains(hour + hoursOffset);
string isSelectedCls = selected(viewTime.Hour + hoursOffset, Value?.Hour);
string disabledCls = disabled ? $"{PrefixCls}-time-panel-cell-disabled" : "";
<li class="@(PrefixCls)-time-panel-cell @isSelectedCls @disabledCls">
<div class="@(PrefixCls)-time-panel-cell-inner"
@onclick="e => { if (!disabled) OnSelectHour(viewTime); }">
@hour
@onclick="e => { if (!disabled) OnSelectHour(viewTime.AddHours(hoursOffset)); }">
@(use12Hours && hour==0? 12 : hour)
</div>
</li>
if (!disabled && selectFirstHour)
{
OnSelectHour(viewTime.AddHours(hoursOffset));
selectFirstHour = false;
}
startTime = startTime.AddHours(1);
}
</ul>
@ -160,6 +172,33 @@
}
</ul>
}
@if (use12Hours)
{
<ul class="@(PrefixCls)-time-panel-column" style="position: relative; overflow: hidden;">
@{
string isAmSelectedCls = isPM || isValueNull ? "" : $"{PrefixCls}-time-panel-cell-selected";
string isPmSelectedCls = isPM ? $"{PrefixCls}-time-panel-cell-selected" : "";
bool disabled = false;
string disabledCls = disabled ? $"{PrefixCls}-time-panel-cell-disabled" : "";
<li class="@(PrefixCls)-time-panel-cell @isAmSelectedCls @disabledCls">
<div class="@(PrefixCls)-time-panel-cell-inner"
@onclick="e => {if (!disabled && (isPM || Value is null)) if(Value is not null) OnSelectHour(Value.Value.AddHours(-12));
else OnSelectTime(DateTime.Today); }">
@System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.AMDesignator
</div>
</li>
<li class="@(PrefixCls)-time-panel-cell @isPmSelectedCls @disabledCls">
<div class="@(PrefixCls)-time-panel-cell-inner"
@onclick="e => {if (!disabled && (!isPM || Value is null)) if(Value is not null) OnSelectHour(Value.Value.AddHours(12));
else OnSelectTime(DateTime.Today.AddHours(12)); }">
@System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator
</div>
</li>
}
</ul>
}
</div>
</div>
</div>

View File

@ -36,22 +36,21 @@ namespace AntDesign.Internal
List<int> disabledMinutes = new List<int>();
List<int> disabledSeconds = new List<int>();
DatePickerDisabledTime userDisabledTime = null;
if (Value is not null)
if (DisabledHours is not null)
{
if (DisabledHours is not null)
{
disabledHours.AddRange(DisabledHours(Value.Value));
}
if (DisabledMinutes is not null)
{
disabledMinutes.AddRange(DisabledMinutes(Value.Value));
}
if (DisabledSeconds is not null)
{
disabledSeconds.AddRange(DisabledSeconds(Value.Value));
}
userDisabledTime = DisabledTime?.Invoke(Value ?? DateTime.Now);
disabledHours.AddRange(DisabledHours(Value ?? DateTime.Now));
}
if (DisabledMinutes is not null)
{
disabledMinutes.AddRange(DisabledMinutes(Value ?? DateTime.Now));
}
if (DisabledSeconds is not null)
{
disabledSeconds.AddRange(DisabledSeconds(Value ?? DateTime.Now));
}
userDisabledTime = DisabledTime?.Invoke(Value ?? DateTime.Now);
if (userDisabledTime != null)
{

View File

@ -86,6 +86,9 @@ namespace AntDesign
[Parameter]
public RenderFragment RenderExtraFooter { get; set; }
[Parameter]
public bool Use12Hours { get; set; }
protected Dictionary<string, object> GetAttributes()
{
return new Dictionary<string, object>()

View File

@ -49,7 +49,7 @@
{
@if (DatePicker.IsShowTime)
{
<DatePickerDatetimePanel TValue="TValue" IsShowTime="@DatePicker.IsShowTime" OnOkClick="DatePicker.OnOkClick" @attributes="dateTimeAttributes" />
<DatePickerDatetimePanel TValue="TValue" IsShowTime="@DatePicker.IsShowTime" Use12Hours="DatePicker.Use12Hours" OnOkClick="DatePicker.OnOkClick" @attributes="dateTimeAttributes" />
}
else
{
@ -78,6 +78,6 @@
}
else if (IsShowTimePanel())
{
<DatePickerDatetimePanel TValue="TValue" @attributes="dateTimeAttributes" />
<DatePickerDatetimePanel TValue="TValue" Use12Hours="DatePicker.Use12Hours" OnOkClick="DatePicker.OnOkClick" @attributes="dateTimeAttributes" />
}
</CascadingValue>

View File

@ -65,5 +65,7 @@ namespace AntDesign
public string QuarterSelect { get; set; } = "Select quarter";
public string Week { get; set; } = "Week";
public string[] ShortWeekDays { get; set; } = new string[] { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" };
public string TimeFormat12Hour { get; set; } = "hh:mm:ss tt";
public string DateTimeFormat12Hour { get; set; } = "yyyy-MM-dd hh:mm:ss tt";
}
}

View File

@ -42,6 +42,8 @@
"dateFormat": "yyyy-MM-dd",
"dayFormat": "d",
"dateTimeFormat": "yyyy-MM-dd HH:mm:ss",
"dateTimeFormat12Hour": "M/d/yyyy hh:mm:ss tt",
"timeFormat12Hour": "hh:mm:ss tt",
"monthBeforeYear": true,
"previousMonth": "Previous month (PageUp)",
"nextMonth": "Next month (PageDown)",
@ -104,6 +106,8 @@
"dateFormat": "M/d/yyyy",
"dayFormat": "d",
"dateTimeFormat": "M/d/yyyy HH:mm:ss",
"dateTimeFormat12Hour": "M/d/yyyy hh:mm:ss tt",
"timeFormat12Hour": "hh:mm:ss tt",
"monthBeforeYear": true,
"previousMonth": "Previous month (PageUp)",
"nextMonth": "Next month (PageDown)",

View File

@ -1,3 +1,3 @@
<div>
TODO
<TimePicker TValue="DateTime?" Use12Hours/>
</div>

View File

@ -7,9 +7,9 @@ title:
## zh-CN
12 小时制的时间选择器,默认的 format 为 `h:mm:ss a`。
12 小时制的时间选择器,默认的 format 为 `hh:mm:ss tt`。
## en-US
TimePicker of 12 hours format, with default format `h:mm:ss a`.
TimePicker of 12 hours format, with default format `hh:mm:ss tt`.