Changed implementation of DateTokens to use localization abstractions. Added more tokens. Beefed up unit tests to cover all tokens.

This commit is contained in:
Daniel Stolt
2014-08-02 21:49:41 +02:00
parent dc21e33294
commit f019392a93
7 changed files with 153 additions and 109 deletions

View File

@@ -2,27 +2,27 @@
namespace Orchard.AuditTrail.Helpers { namespace Orchard.AuditTrail.Helpers {
public static class DateTimeExtensions { public static class DateTimeExtensions {
public static DateTime? Earliest(this DateTime? value) { public static DateTime StartOfDay(this DateTime value) {
if (value == null)
return null;
return Earliest(value.Value);
}
public static DateTime Earliest(this DateTime value) {
return new DateTime(value.Year, value.Month, value.Day, 0, 0, 0, 0, value.Kind); return new DateTime(value.Year, value.Month, value.Day, 0, 0, 0, 0, value.Kind);
} }
public static DateTime? Latest(this DateTime? value) { public static DateTime? StartOfDay(this DateTime? value) {
if (value == null)
return null;
return StartOfDay(value.Value);
}
public static DateTime EndOfDay(this DateTime value) {
return new DateTime(value.Year, value.Month, value.Day, 23, 59, 59, 999, value.Kind);
}
public static DateTime? EndOfDay(this DateTime? value) {
if (value == null) if (value == null)
return null; return null;
var v = value.Value; var v = value.Value;
return new DateTime(v.Year, v.Month, v.Day, 23, 59, 59, 999, v.Kind); return new DateTime(v.Year, v.Month, v.Day, 23, 59, 59, 999, v.Kind);
} }
public static DateTime Latest(this DateTime value) {
return new DateTime(value.Year, value.Month, value.Day, 23, 59, 59, 999, value.Kind);
}
} }
} }

View File

@@ -206,7 +206,7 @@ namespace Orchard.AuditTrail.Services {
} }
public IEnumerable<AuditTrailEventRecord> Trim(TimeSpan retentionPeriod) { public IEnumerable<AuditTrailEventRecord> Trim(TimeSpan retentionPeriod) {
var dateThreshold = (_clock.UtcNow.Latest() - retentionPeriod); var dateThreshold = (_clock.UtcNow.EndOfDay() - retentionPeriod);
var query = _auditTrailRepository.Table.Where(x => x.CreatedUtc <= dateThreshold); var query = _auditTrailRepository.Table.Where(x => x.CreatedUtc <= dateThreshold);
var records = query.ToArray(); var records = query.ToArray();

View File

@@ -18,8 +18,8 @@ namespace Orchard.AuditTrail.Services {
public override void Filter(QueryFilterContext context) { public override void Filter(QueryFilterContext context) {
var userName = context.Filters.Get("username"); var userName = context.Filters.Get("username");
var category = context.Filters.Get("category"); var category = context.Filters.Get("category");
var from = GetDateFromFilter(context.Filters, "From", "from").Earliest(); var from = GetDateFromFilter(context.Filters, "From", "from").StartOfDay();
var to = GetDateFromFilter(context.Filters, "To", "to").Latest(); var to = GetDateFromFilter(context.Filters, "To", "to").EndOfDay();
var query = context.Query; var query = context.Query;
if (!String.IsNullOrWhiteSpace(userName)) { if (!String.IsNullOrWhiteSpace(userName)) {
@@ -57,13 +57,12 @@ namespace Orchard.AuditTrail.Services {
} }
private DateTime? GetDateFromFilter(Filters filters, string fieldName, string prefix) { private DateTime? GetDateFromFilter(Filters filters, string fieldName, string prefix) {
var dateString = filters.Get(prefix + ".Date");
try { try {
var dateString = filters.Get(prefix + ".Date"); return _dateLocalizationServices.ConvertFromLocalizedDateString(dateString);
var timeString = filters.Get(prefix + ".Time");
return _dateLocalizationServices.ConvertFromLocalizedString(dateString, timeString);
} }
catch (FormatException ex) { catch (FormatException ex) {
filters.UpdateModel.AddModelError(prefix, T(@"Error parsing ""{0}"" date: {1}", fieldName, ex.Message)); filters.UpdateModel.AddModelError(prefix, T(@"Error parsing '{0}' date string '{1}': {2}", fieldName, dateString, ex.Message));
return null; return null;
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Localization.Models;
using Orchard.Localization.Services; using Orchard.Localization.Services;
using Orchard.Mvc.Html; using Orchard.Mvc.Html;
using Orchard.Services; using Orchard.Services;
@@ -8,66 +9,79 @@ using Orchard.Services;
namespace Orchard.Tokens.Providers { namespace Orchard.Tokens.Providers {
public class DateTokens : ITokenProvider { public class DateTokens : ITokenProvider {
private readonly IClock _clock; private readonly IClock _clock;
private readonly IDateTimeFormatProvider _dateTimeLocalization;
private readonly IWorkContextAccessor _workContextAccessor; private readonly IWorkContextAccessor _workContextAccessor;
private readonly Lazy<CultureInfo> _cultureInfo; private readonly IDateTimeFormatProvider _dateTimeFormats;
private readonly IDateFormatter _dateFormatter;
private readonly IDateLocalizationServices _dateLocalizationServices; private readonly IDateLocalizationServices _dateLocalizationServices;
//private readonly Lazy<CultureInfo> _cultureInfo;
public DateTokens( public DateTokens(
IClock clock, IClock clock,
IDateTimeFormatProvider dateTimeLocalization,
IWorkContextAccessor workContextAccessor, IWorkContextAccessor workContextAccessor,
IDateLocalizationServices dateServices) { IDateTimeFormatProvider dateTimeFormats,
IDateFormatter dateFormatter,
IDateLocalizationServices dateLocalizationServices) {
_clock = clock; _clock = clock;
_dateTimeLocalization = dateTimeLocalization;
_workContextAccessor = workContextAccessor; _workContextAccessor = workContextAccessor;
_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(_workContextAccessor.GetContext().CurrentCulture)); _dateTimeFormats = dateTimeFormats;
_dateLocalizationServices = dateServices; _dateFormatter = dateFormatter;
_dateLocalizationServices = dateLocalizationServices;
//_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(_workContextAccessor.GetContext().CurrentCulture));
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
public Localizer T { get; set; } public Localizer T { get; set; }
public void Describe(DescribeContext context) { public void Describe(DescribeContext context) {
context.For("Date", T("Date/time"), T("Current date/time tokens")) context.For("Date", T("Date/Time"), T("Current date/time tokens"))
.Token("Since", T("Since"), T("Relative to the current date/time."), "Date") .Token("Since", T("Since"), T("Relative to the current date/time."), "Date")
.Token("Local", T("Local"), T("Based on the configured time zone and calendar."), "Date") .Token("Local", T("Local"), T("Based on the configured time zone and calendar."), "Date")
.Token("Short", T("Short Date and Time"), T("Short date and time format."))
.Token("ShortDate", T("Short Date"), T("Short date format.")) .Token("ShortDate", T("Short Date"), T("Short date format."))
.Token("ShortTime", T("Short Time"), T("Short time format.")) .Token("ShortTime", T("Short Time"), T("Short time format."))
.Token("Long", T("Long Date and Time"), T("Long date and time format.")) .Token("Long", T("Long Date and Time"), T("Long date and time format."))
.Token("Format:*", T("Format:<date format>"), T("Optional format specifier (e.g. yyyy/MM/dd). See format strings at <a target=\"_blank\" href=\"http://msdn.microsoft.com/en-us/library/az4se3k1.aspx\">Standard Formats</a> and <a target=\"_blank\" href=\"http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx\">Custom Formats</a>"), "DateTime"); .Token("LongDate", T("Long Date"), T("Long date format."))
.Token("LongTime", T("Long Time"), T("Long time format."))
.Token("Format:*", T("Format:<formatString>"), T("Optional custom date/time format string (e.g. yyyy/MM/dd). For reference see <a target=\"_blank\" href=\"http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx\">Custom Date and Time Format Strings</a>"), "DateTime");
} }
public void Evaluate(EvaluateContext context) { public void Evaluate(EvaluateContext context) {
context.For("Date", () => _clock.UtcNow) context.For("Date", () => _clock.UtcNow)
// {Date.Since} // {Date.Since}
.Token("Since", DateTimeRelative) .Token("Since", DateTimeRelative)
.Chain("Since", "Date", DateTimeRelative)
// {Date.Local} // {Date.Local}
.Token("Local", d => _dateLocalizationServices.ConvertToSiteTimeZone(d)) .Token("Local", d => _dateLocalizationServices.ConvertToLocalizedString(d))
.Chain("Local", "Date", d => _dateLocalizationServices.ConvertToSiteTimeZone(d)) .Chain("Local", "Date", d => _dateLocalizationServices.ConvertToSiteTimeZone(d))
// {Date.Short}
.Token("Short", d => _dateLocalizationServices.ConvertToLocalizedString(d, _dateTimeFormats.ShortDateTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false }))
// {Date.ShortDate} // {Date.ShortDate}
.Token("ShortDate", d => d.ToString(_dateTimeLocalization.ShortDateFormat, _cultureInfo.Value)) .Token("ShortDate", d => _dateLocalizationServices.ConvertToLocalizedString(d, _dateTimeFormats.ShortDateFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false }))
// {Date.ShortTime} // {Date.ShortTime}
.Token("ShortTime", d => d.ToString(_dateTimeLocalization.ShortTimeFormat, _cultureInfo.Value)) .Token("ShortTime", d => _dateLocalizationServices.ConvertToLocalizedString(d, _dateTimeFormats.ShortTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false }))
// {Date.Long} // {Date.Long}
.Token("Long", d => d.ToString(_dateTimeLocalization.LongDateTimeFormat, _cultureInfo.Value)) .Token("Long", d => _dateLocalizationServices.ConvertToLocalizedString(d, _dateTimeFormats.LongDateTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false }))
// {Date.LongDate}
.Token("LongDate", d => _dateLocalizationServices.ConvertToLocalizedString(d, _dateTimeFormats.LongDateFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false }))
// {Date.LongTime}
.Token("LongTime", d => _dateLocalizationServices.ConvertToLocalizedString(d, _dateTimeFormats.LongTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false }))
// {Date} // {Date}
.Token( .Token(
token => token == String.Empty ? String.Empty : null, token => token == String.Empty ? String.Empty : null,
(token, d) => d.ToString(_dateTimeLocalization.ShortDateFormat + " " + _dateTimeLocalization.ShortTimeFormat, _cultureInfo.Value)) (token, d) => _dateLocalizationServices.ConvertToLocalizedString(d, new DateLocalizationOptions() { EnableTimeZoneConversion = false }))
// {Date.Format:<formatstring>} // {Date.Format:<formatString>}
.Token( .Token(
token => token.StartsWith("Format:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Format:".Length) : null, token => token.StartsWith("Format:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Format:".Length) : null,
(token, d) => d.ToString(token, _cultureInfo.Value)); (token, d) => _dateLocalizationServices.ConvertToLocalizedString(d, token, new DateLocalizationOptions() { EnableTimeZoneConversion = false }));
} }
private string DateTimeRelative(DateTime dateTimeUtc) { private string DateTimeRelative(DateTime dateTimeUtc) {
var time = _clock.UtcNow - dateTimeUtc.ToUniversalTime(); var time = _clock.UtcNow - dateTimeUtc.ToUniversalTime();
if (time.TotalDays > 7) if (time.TotalDays > 7)
return dateTimeUtc.ToString(T("'on' MMM d yyyy 'at' h:mm tt").ToString(), _cultureInfo.Value); return _dateFormatter.FormatDateTime(DateTimeParts.FromDateTime(dateTimeUtc), T("'on' MMM d yyyy 'at' h:mm tt").ToString());
if (time.TotalHours > 24) if (time.TotalHours > 24)
return T.Plural("1 day ago", "{0} days ago", time.Days).ToString(); return T.Plural("1 day ago", "{0} days ago", time.Days).ToString();
if (time.TotalMinutes > 60) if (time.TotalMinutes > 60)

View File

@@ -6,6 +6,7 @@ using Orchard.Localization.Services;
using Orchard.Services; using Orchard.Services;
using Orchard.Tokens.Implementation; using Orchard.Tokens.Implementation;
using Orchard.Tokens.Providers; using Orchard.Tokens.Providers;
using Orchard.Localization.Models;
namespace Orchard.Tokens.Tests { namespace Orchard.Tokens.Tests {
[TestFixture] [TestFixture]
@@ -13,6 +14,9 @@ namespace Orchard.Tokens.Tests {
private IContainer _container; private IContainer _container;
private ITokenizer _tokenizer; private ITokenizer _tokenizer;
private IClock _clock; private IClock _clock;
private IDateTimeFormatProvider _dateTimeFormats;
private IDateLocalizationServices _dateLocalizationServices;
private IDateFormatter _dateFormatter;
[SetUp] [SetUp]
public void Init() { public void Init() {
@@ -22,39 +26,107 @@ namespace Orchard.Tokens.Tests {
builder.RegisterType<Tokenizer>().As<ITokenizer>(); builder.RegisterType<Tokenizer>().As<ITokenizer>();
builder.RegisterType<DateTokens>().As<ITokenProvider>(); builder.RegisterType<DateTokens>().As<ITokenProvider>();
builder.RegisterType<StubClock>().As<IClock>(); builder.RegisterType<StubClock>().As<IClock>();
builder.RegisterType<CultureDateTimeFormatProvider>().As<IDateTimeFormatProvider>();
builder.RegisterType<DefaultDateFormatter>().As<IDateFormatter>();
builder.RegisterType<DefaultDateLocalizationServices>().As<IDateLocalizationServices>();
builder.RegisterType<StubWorkContextAccessor>().As<IWorkContextAccessor>(); builder.RegisterType<StubWorkContextAccessor>().As<IWorkContextAccessor>();
builder.RegisterType<SiteCalendarSelector>().As<ICalendarSelector>(); builder.RegisterType<SiteCalendarSelector>().As<ICalendarSelector>();
builder.RegisterType<DefaultCalendarManager>().As<ICalendarManager>(); builder.RegisterType<DefaultCalendarManager>().As<ICalendarManager>();
builder.RegisterType<CultureDateTimeFormatProvider>().As<IDateTimeFormatProvider>();
builder.RegisterType<DefaultDateFormatter>().As<IDateFormatter>();
builder.RegisterType<DefaultDateLocalizationServices>().As<IDateLocalizationServices>();
_container = builder.Build(); _container = builder.Build();
_tokenizer = _container.Resolve<ITokenizer>(); _tokenizer = _container.Resolve<ITokenizer>();
_clock = _container.Resolve<IClock>(); _clock = _container.Resolve<IClock>();
_dateTimeFormats = _container.Resolve<IDateTimeFormatProvider>();
_dateLocalizationServices = _container.Resolve<IDateLocalizationServices>();
_dateFormatter = _container.Resolve<IDateFormatter>();
} }
[Test] [Test]
public void TestDateTokens() { public void TestDate() {
var dateTimeLocalization = _container.Resolve<IDateTimeFormatProvider>(); Assert.That(_tokenizer.Replace("{Date}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
var culture = CultureInfo.GetCultureInfo(_container.Resolve<IOrchardServices>().WorkContext.CurrentCulture); Assert.That(_tokenizer.Replace("{Date}", new { Date = new DateTime(1978, 11, 15, 0, 0, 0, DateTimeKind.Utc) }), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(new DateTime(1978, 11, 15, 0, 0, 0, DateTimeKind.Utc), new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
var dateTimeFormat = dateTimeLocalization.ShortDateFormat + " " + dateTimeLocalization.ShortTimeFormat;
Assert.That(_tokenizer.Replace("{Date}", null), Is.EqualTo(_clock.UtcNow.ToString(dateTimeFormat, culture)));
Assert.That(_tokenizer.Replace("{Date}", new { Date = new DateTime(1978, 11, 15, 0, 0, 0, DateTimeKind.Utc) }), Is.EqualTo(new DateTime(1978, 11, 15, 0, 0, 0, DateTimeKind.Utc).ToString(dateTimeFormat, culture)));
} }
[Test] [Test]
public void TestFormat() { public void TestDateSince() {
Assert.That(_tokenizer.Replace("{Date.Format:yyyy}", null), Is.EqualTo(_clock.UtcNow.ToString("yyyy"))); var date = _clock.UtcNow.AddHours(-25);
}
[Test]
public void TestSince() {
var date = _clock.UtcNow.Subtract(TimeSpan.FromHours(25));
Assert.That(_tokenizer.Replace("{Date.Since}", new { Date = date }), Is.EqualTo("1 day ago")); Assert.That(_tokenizer.Replace("{Date.Since}", new { Date = date }), Is.EqualTo("1 day ago"));
} }
[Test]
public void TestDateShort() {
Assert.That(_tokenizer.Replace("{Date.Short}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.ShortDateTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
}
[Test]
public void TestDateShortDate() {
Assert.That(_tokenizer.Replace("{Date.ShortDate}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.ShortDateFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
}
[Test]
public void TestDateShortTime() {
Assert.That(_tokenizer.Replace("{Date.ShortTime}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.ShortTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
}
[Test]
public void TestDateLong() {
Assert.That(_tokenizer.Replace("{Date.Long}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.LongDateTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
}
[Test]
public void TestDateLongDate() {
Assert.That(_tokenizer.Replace("{Date.LongDate}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.LongDateFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
}
[Test]
public void TestDateLongTime() {
Assert.That(_tokenizer.Replace("{Date.LongTime}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.LongTimeFormat, new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
}
[Test]
public void TestDateFormat() {
Assert.That(_tokenizer.Replace("{Date.Format:yyyyMMdd}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, "yyyyMMdd", new DateLocalizationOptions() { EnableTimeZoneConversion = false })));
}
[Test]
public void TestDateLocal() {
Assert.That(_tokenizer.Replace("{Date.Local}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow)));
Assert.That(_tokenizer.Replace("{Date.Local}", new { Date = new DateTime(1978, 11, 15, 0, 0, 0, DateTimeKind.Utc) }), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(new DateTime(1978, 11, 15, 0, 0, 0, DateTimeKind.Utc))));
}
[Test]
public void TestDateLocalShort() {
Assert.That(_tokenizer.Replace("{Date.Local.Short}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.ShortDateTimeFormat)));
}
[Test]
public void TestDateLocalShortDate() {
Assert.That(_tokenizer.Replace("{Date.Local.ShortDate}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.ShortDateFormat)));
}
[Test]
public void TestDateLocalShortTime() {
Assert.That(_tokenizer.Replace("{Date.Local.ShortTime}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.ShortTimeFormat)));
}
[Test]
public void TestDateLocalLong() {
Assert.That(_tokenizer.Replace("{Date.Local.Long}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.LongDateTimeFormat)));
}
[Test]
public void TestDateLocalLongDate() {
Assert.That(_tokenizer.Replace("{Date.Local.LongDate}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.LongDateFormat)));
}
[Test]
public void TestDateLocalLongTime() {
Assert.That(_tokenizer.Replace("{Date.Local.LongTime}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, _dateTimeFormats.LongTimeFormat)));
}
[Test]
public void TestDateLocalFormat() {
Assert.That(_tokenizer.Replace("{Date.Local.Format:yyyyMMdd}", null), Is.EqualTo(_dateLocalizationServices.ConvertToLocalizedString(_clock.UtcNow, "yyyyMMdd")));
}
} }
} }

View File

@@ -37,7 +37,7 @@ namespace Orchard.Tokens.Tests {
_initMethod(this); _initMethod(this);
} }
_contextDictonary["CurrentTimeZone"] = TimeZoneInfo.Local; _contextDictonary["CurrentTimeZone"] = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
_contextDictonary["CurrentCulture"] = "en-US"; _contextDictonary["CurrentCulture"] = "en-US";
_contextDictonary["CurrentCalendar"] = null; _contextDictonary["CurrentCalendar"] = null;
} }

View File

@@ -1,53 +1,12 @@
DateTime? ConvertToSiteTimeZone(DateTime? date)
DateTime? ConvertFromSiteTimeZone(DateTime? date)
- Also provides overloads with non-nullable DateTime parameters for compatibility with existing callers.
- Does only time zone conversion. No calendar conversion.
DateTimeParts? ConvertToSiteCalendar(DateTime? date)
DateTime? ConvertFromSiteCalendar(Parts? dateParts)
- Does only calendar conversion. No time zone conversion.
- Instantiates the site calendar and does "manual" conversion.
- Uses a custom storage structure DateTimeParts for non-gregorian representation.
string ConvertToLocalizedDateString(DateTime? date, DateLocalizationOptions options = DateLocalizationOptions.Default)
string ConvertToLocalizedTimeString(DateTime? date, DateLocalizationOptions options = DateLocalizationOptions.Default)
string ConvertToLocalizedString(DateTime? date, DateLocalizationOptions options)
string ConvertToLocalizedString(DateTime? date, string format, DateLocalizationOptions options)
- Also provides overloads with non-nullable DateTime parameters for compatibility with existing callers.
- By default performs the full conversion (time zone, calendar and formatting). Can be overridden by DateLocalizationOptions.
- If NOT ConvertCalendar, uses DateTime.ToString() with an cloned CultureInfo using GregorianCalendar of type Localized.
- If ConvertCalendar and UNSUPPORTED non-default calendar, uses ConvertToSiteCalendar() and Mahsa's custom formatting.
- If ConvertCalendar and SUPPORTED non-default calendar, uses DateTime.ToString() with cloned CultureInfo using an optional calendar instance, which does both calendar conversion and formatting.
- Otherwise uses DateTime.ToString() with configured CultureInfo which does both calendar conversion and formatting.
DateTime? ConvertFromLocalizedDateString(string dateString, DateLocalizationOptions options = DateLocalizationOptions.Default)
DateTime? ConvertFromLocalizedTimeString(string timeString, DateLocalizationOptions options = DateLocalizationOptions.Default)
DateTime? ConvertFromLocalizedString(string dateTimeString, DateLocalizationOptions options = DateLocalizationOptions.Default)
DateTime? ConvertFromLocalizedString(string dateString, string timeString, DateLocalizationOptions options = DateLocalizationOptions.Default)
- By default performs the full conversion (parsing, calendar and time zone). Can be overridden by DateLocalizationOptions.
- ConvertFromLocalizedDateString() returns a DateTime? with the time component set to 00:00:00. ConvertTimeZone is ignored.
- ConvertFromLocalizedTimeString() returns a DateTime? with the date component set to DateTime.MinValue. ConvertCalendar is ignored.
- If NOT ConvertCalendar, uses DateTime.Parse() with an cloned CultureInfo using GregorianCalendar of type Localized.
- If ConvertCalendar and UNSUPPORTED non-default calendar, uses Mahsa's custom parsing and ConvertToSiteCalendar().
- If ConvertCalendar and SUPPORTED non-default calendar, uses DateTime.Parse() with cloned CultureInfo using an optional calendar instance, which does both parsing and calendar conversion.
- Otherwise uses DateTime.Parse() with configured CultureInfo which does both parsing and calendar conversion.
- ConvertFromLocalizedString() with dateString or timeString set to null is the same as ConvertFromLocalizedTimeString() and ConvertFromLocalizedDateString() respectively.
- Checks if the parsed string matches NullText, and if so returns null.
struct DateLocalizationOptions {
bool ConvertTimeZone;
bool ConvertCalendar;
string NullText;
}
TODO: TODO:
* Test for proper handling of fraction (f) format specifier - suspect it does not work properly in current state * Test for proper handling of fraction (f) format specifier - suspect it does not work properly in current state
* Add formatting and parsing of time zone information (add timezone properties to TimeParts structure) * Add formatting and parsing of time zone information (add timezone properties to TimeParts structure)
* Write unit tests for DefaultDateLocalizationServices * Write unit tests for DefaultDateLocalizationServices
* Add warning message when saving unsupported combination in settings * Add warning message when saving unsupported combination in settings
* Add support for the different Gregorian calendar types * Add support for the different Gregorian calendar types
* Go over date conversion logic in audit trail filtering to make sure it's correct * Improve DateTimeField:
* Go over date conversion logic in DateTokens to make sure it's correct - Surface the field mode (date, time or both)
* Improve DateTimeField: - Do not perform time-zone conversion in date-only mode
- Surface the field mode (date, time or both)
- Do not perform time-zone conversion in date-only mode BREAKING:
* DateTokens "Date.Format:<formatString>" and "Date.Local.Format:<formatString>" only supports custom date/time format strings.