mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Added format-specific overloads to IDateFormatter and DefaultDateFormatter for performance optimization.
This commit is contained in:
@@ -41,7 +41,7 @@ namespace Orchard.Framework.Tests.Localization {
|
||||
var cultureGregorian = (CultureInfo)culture.Clone();
|
||||
cultureGregorian.DateTimeFormat.Calendar = cultureGregorian.OptionalCalendars.OfType<GregorianCalendar>().First();
|
||||
var dateTimeString = dateTime.ToString(dateTimeFormat, cultureGregorian);
|
||||
var result = target.ParseDateTime(dateTimeString);
|
||||
var result = target.ParseDateTime(dateTimeString, dateTimeFormat);
|
||||
var reference = DateTime.ParseExact(dateTimeString, dateTimeFormat, culture);
|
||||
var expected = new DateTimeParts(reference.Year, reference.Month, reference.Day, reference.Hour, reference.Minute, reference.Second, reference.Millisecond);
|
||||
Assert.AreEqual(expected, result);
|
||||
@@ -74,7 +74,7 @@ namespace Orchard.Framework.Tests.Localization {
|
||||
foreach (var dateFormat in formats.AllDateFormats) { // All date formats supported by the culture.
|
||||
var caseKey = String.Format("{0}:{1}", culture.Name, dateFormat);
|
||||
allCases.Add(caseKey);
|
||||
Debug.WriteLine(String.Format("{0} cases tested so far. Testing case {1}...", allCases.Count, caseKey));
|
||||
//Debug.WriteLine(String.Format("{0} cases tested so far. Testing case {1}...", allCases.Count, caseKey));
|
||||
try {
|
||||
for (var month = 1; month <= 12; month++) { // All months in the year.
|
||||
DateTime date = new DateTime(1998, month, 1);
|
||||
@@ -82,7 +82,7 @@ namespace Orchard.Framework.Tests.Localization {
|
||||
var cultureGregorian = (CultureInfo)culture.Clone();
|
||||
cultureGregorian.DateTimeFormat.Calendar = cultureGregorian.OptionalCalendars.OfType<GregorianCalendar>().First();
|
||||
var dateString = date.ToString(dateFormat, cultureGregorian);
|
||||
var result = target.ParseDate(dateString);
|
||||
var result = target.ParseDate(dateString, dateFormat);
|
||||
var expected = new DateParts(date.Year, date.Month, date.Day);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
@@ -113,12 +113,12 @@ namespace Orchard.Framework.Tests.Localization {
|
||||
foreach (var timeFormat in formats.AllTimeFormats) { // All time formats supported by the culture.
|
||||
var caseKey = String.Format("{0}:{1}", culture.Name, timeFormat);
|
||||
allCases.Add(caseKey);
|
||||
Debug.WriteLine(String.Format("{0} cases tested so far. Testing case {1}...", allCases.Count, caseKey));
|
||||
//Debug.WriteLine(String.Format("{0} cases tested so far. Testing case {1}...", allCases.Count, caseKey));
|
||||
try {
|
||||
for (var hour = 0; hour <= 23; hour++) { // All hours in the day.
|
||||
DateTime time = new DateTime(1998, 1, 1, hour, 30, 30);
|
||||
var timeString = time.ToString(timeFormat, culture);
|
||||
var result = target.ParseTime(timeString);
|
||||
var result = target.ParseTime(timeString, timeFormat);
|
||||
var reference = DateTime.ParseExact(timeString, timeFormat, culture);
|
||||
var expected = new TimeParts(reference.Hour, reference.Minute, reference.Second, reference.Millisecond);
|
||||
Assert.AreEqual(expected, result);
|
||||
|
@@ -28,44 +28,74 @@ namespace Orchard.Framework.Localization.Services {
|
||||
var replacements = GetDateParseReplacements().Concat(GetTimeParseReplacements()).ToDictionary(item => item.Key, item => item.Value);
|
||||
|
||||
foreach (var dateTimeFormat in _dateTimeFormatProvider.AllDateTimeFormats) {
|
||||
var dateTimePattern = ConvertFormatStringToRegexPattern(dateTimeFormat, replacements);
|
||||
Match m = Regex.Match(dateTimeString.Trim(), dateTimePattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success) {
|
||||
return new DateTimeParts(ExtractDateParts(m), ExtractTimeParts(m));
|
||||
var result = TryParseDateTime(dateTimeString, dateTimeFormat, replacements);
|
||||
if (result.HasValue) {
|
||||
return result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
throw new FormatException("The string was not recognized as a valid date and time.");
|
||||
}
|
||||
|
||||
public virtual DateTimeParts ParseDateTime(string dateTimeString, string format) {
|
||||
var replacements = GetDateParseReplacements().Concat(GetTimeParseReplacements()).ToDictionary(item => item.Key, item => item.Value);
|
||||
|
||||
var result = TryParseDateTime(dateTimeString, format, replacements);
|
||||
if (result.HasValue) {
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
throw new FormatException("The string was not recognized as a valid date and time.");
|
||||
}
|
||||
|
||||
public virtual DateParts ParseDate(string dateString) {
|
||||
var replacements = GetDateParseReplacements();
|
||||
|
||||
foreach (var dateFormat in _dateTimeFormatProvider.AllDateFormats) {
|
||||
var datePattern = ConvertFormatStringToRegexPattern(dateFormat, replacements);
|
||||
Match m = Regex.Match(dateString.Trim(), datePattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success) {
|
||||
return ExtractDateParts(m);
|
||||
var result = TryParseDate(dateString, dateFormat, replacements);
|
||||
if (result.HasValue) {
|
||||
return result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
throw new FormatException("The string was not recognized as a valid date.");
|
||||
}
|
||||
|
||||
public virtual DateParts ParseDate(string dateString, string format) {
|
||||
var replacements = GetDateParseReplacements();
|
||||
|
||||
var result = TryParseDate(dateString, format, replacements);
|
||||
if (result.HasValue) {
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
throw new FormatException("The string was not recognized as a valid date.");
|
||||
}
|
||||
|
||||
public virtual TimeParts ParseTime(string timeString) {
|
||||
var replacements = GetTimeParseReplacements();
|
||||
|
||||
foreach (var timeFormat in _dateTimeFormatProvider.AllTimeFormats) {
|
||||
var timePattern = ConvertFormatStringToRegexPattern(timeFormat, replacements);
|
||||
Match m = Regex.Match(timeString.Trim(), timePattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success) {
|
||||
return ExtractTimeParts(m);
|
||||
var result = TryParseTime(timeString, timeFormat, replacements);
|
||||
if (result.HasValue) {
|
||||
return result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
throw new FormatException("The string was not recognized as a valid time.");
|
||||
}
|
||||
|
||||
public virtual TimeParts ParseTime(string timeString, string format) {
|
||||
var replacements = GetTimeParseReplacements();
|
||||
|
||||
var result = TryParseTime(timeString, format, replacements);
|
||||
if (result.HasValue) {
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
throw new FormatException("The string was not recognized as a valid time.");
|
||||
}
|
||||
|
||||
public virtual string FormatDateTime(DateTimeParts parts) {
|
||||
// TODO: Mahsa should implement!
|
||||
throw new NotImplementedException();
|
||||
@@ -96,12 +126,41 @@ namespace Orchard.Framework.Localization.Services {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual DateTimeParts? TryParseDateTime(string dateTimeString, string format, IDictionary<string, string> replacements) {
|
||||
var dateTimePattern = ConvertFormatStringToRegexPattern(format, replacements);
|
||||
Match m = Regex.Match(dateTimeString.Trim(), dateTimePattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success) {
|
||||
return new DateTimeParts(ExtractDateParts(m), ExtractTimeParts(m));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual DateParts? TryParseDate(string dateString, string format, IDictionary<string, string> replacements) {
|
||||
var datePattern = ConvertFormatStringToRegexPattern(format, replacements);
|
||||
Match m = Regex.Match(dateString.Trim(), datePattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success) {
|
||||
return ExtractDateParts(m);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual TimeParts? TryParseTime(string timeString, string format, IDictionary<string, string> replacements) {
|
||||
var timePattern = ConvertFormatStringToRegexPattern(format, replacements);
|
||||
Match m = Regex.Match(timeString.Trim(), timePattern, RegexOptions.IgnoreCase);
|
||||
if (m.Success) {
|
||||
return ExtractTimeParts(m);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual DateParts ExtractDateParts(Match m) {
|
||||
int year = 0,
|
||||
month = 0,
|
||||
day = 0;
|
||||
|
||||
year = CurrentCalendar.ToFourDigitYear(Int32.Parse(m.Groups["year"].Value));
|
||||
if (m.Groups["year"].Success) {
|
||||
year = CurrentCalendar.ToFourDigitYear(Int32.Parse(m.Groups["year"].Value));
|
||||
}
|
||||
|
||||
// For the month we can either use the month number, the abbreviated month name or the full month name.
|
||||
if (m.Groups["month"].Success) {
|
||||
@@ -114,7 +173,9 @@ namespace Orchard.Framework.Localization.Services {
|
||||
month = _dateTimeFormatProvider.MonthNames.Select(x => x.ToLowerInvariant()).ToList().IndexOf(m.Groups["monthName"].Value.ToLowerInvariant()) + 1;
|
||||
}
|
||||
|
||||
day = Int32.Parse(m.Groups["day"].Value);
|
||||
if (m.Groups["day"].Success) {
|
||||
day = Int32.Parse(m.Groups["day"].Value);
|
||||
}
|
||||
|
||||
return new DateParts(year, month, day);
|
||||
}
|
||||
|
@@ -7,8 +7,11 @@ using Orchard.Framework.Localization.Models;
|
||||
namespace Orchard.Framework.Localization.Services {
|
||||
public interface IDateFormatter : IDependency {
|
||||
DateTimeParts ParseDateTime(string dateTimeString);
|
||||
DateTimeParts ParseDateTime(string dateTimeString, string format);
|
||||
DateParts ParseDate(string dateString);
|
||||
DateParts ParseDate(string dateString, string format);
|
||||
TimeParts ParseTime(string timeString);
|
||||
TimeParts ParseTime(string timeString, string format);
|
||||
string FormatDateTime(DateTimeParts parts);
|
||||
string FormatDateTime(DateTimeParts parts, string format);
|
||||
string FormatDate(DateParts parts);
|
||||
|
@@ -41,6 +41,9 @@ struct DateLocalizationOptions {
|
||||
}
|
||||
|
||||
TODO:
|
||||
* Add ability to analyze format string to determine which parts we might reasonably expect back from parsing
|
||||
- 4-digit year or only 2-digit so we must infer century?
|
||||
- Which components are present?
|
||||
* Rewrite DefaultDateLocalizationServices
|
||||
* Write unit tests for DefaultDateLocalizationServices
|
||||
* Add warning message when saving unsupported combination in settings
|
||||
|
Reference in New Issue
Block a user