@Html.ActionLink(T("Add or remove supported cultures for the site.").ToString(), "Culture")
+
@Html.EditorFor(x => x.PageTitleSeparator)
diff --git a/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs b/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs
index 7270d01fa..ab9c39fa6 100644
--- a/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs
+++ b/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs
@@ -7,22 +7,27 @@ using Orchard.Mvc.Html;
using Orchard.Services;
namespace Orchard.Core.Shapes {
- public class DateTimeShapes : ISingletonDependency {
+ public class DateTimeShapes : IDependency {
private readonly IClock _clock;
+ private readonly IWorkContextAccessor _workContextAccessor;
- public DateTimeShapes(IClock clock) {
+ public DateTimeShapes(
+ IClock clock,
+ IWorkContextAccessor workContextAccessor
+ ) {
_clock = clock;
+ _workContextAccessor = workContextAccessor;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
[Shape]
- public IHtmlString DateTimeRelative(HtmlHelper Html, DateTime dateTimeUtc) {
+ public IHtmlString DateTimeRelative(dynamic Display, DateTime dateTimeUtc) {
var time = _clock.UtcNow - dateTimeUtc;
if (time.TotalDays > 7)
- return Html.DateTime(dateTimeUtc.ToLocalTime(), T("'on' MMM d yyyy 'at' h:mm tt"));
+ return Display.DateTime(DateTimeUtc: dateTimeUtc, CustomFormat: T("'on' MMM d yyyy 'at' h:mm tt"));
if (time.TotalHours > 24)
return T.Plural("1 day ago", "{0} days ago", time.Days);
if (time.TotalMinutes > 60)
@@ -34,5 +39,30 @@ namespace Orchard.Core.Shapes {
return T("a moment ago");
}
+
+ [Shape]
+ public IHtmlString DateTime(DateTime DateTimeUtc, LocalizedString CustomFormat) {
+ //using a LocalizedString forces the caller to use a localizable format
+
+ if (CustomFormat == null || String.IsNullOrWhiteSpace(CustomFormat.Text)) {
+ return DateTime(DateTimeUtc, T("MMM d yyyy h:mm tt"));
+ }
+
+ return new MvcHtmlString(ConvertToDisplayTime(DateTimeUtc).ToString(CustomFormat.Text));
+ }
+
+ ///
+ /// Converts a Coordinated Universal Time (UTC) to the time in the current time zone.
+ ///
+ ///
The Coordinated Universal Time (UTC).
+ ///
The date and time in the selected time zone. Its System.DateTime.Kind property is System.DateTimeKind.Utc if the current zone is System.TimeZoneInfo.Utc; otherwise, its System.DateTime.Kind property is System.DateTimeKind.Unspecified.
+ private DateTime ConvertToDisplayTime(DateTime dateTimeUtc) {
+
+ // get the time zone for the current request
+ var timeZone = _workContextAccessor.GetContext().CurrentTimeZone;
+
+ return TimeZoneInfo.ConvertTimeFromUtc(dateTimeUtc, timeZone);
+ }
+
}
}
diff --git a/src/Orchard.Web/Modules/Orchard.ArchiveLater/Views/Parts/ArchiveLater.Metadata.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.ArchiveLater/Views/Parts/ArchiveLater.Metadata.SummaryAdmin.cshtml
index 35d3625f1..a9b35ac90 100644
--- a/src/Orchard.Web/Modules/Orchard.ArchiveLater/Views/Parts/ArchiveLater.Metadata.SummaryAdmin.cshtml
+++ b/src/Orchard.Web/Modules/Orchard.ArchiveLater/Views/Parts/ArchiveLater.Metadata.SummaryAdmin.cshtml
@@ -4,7 +4,7 @@
-
@T("Unpublish on")
- @Html.DateTime((DateTime)Model.ScheduledArchiveUtc.ToLocalTime(), T("M/d/yyyy h:mm tt"))
+ @Display.DateTime(DateTimeUtc: (DateTime)Model.ScheduledArchiveUtc.ToLocalTime(), CustomFormat: T("M/d/yyyy h:mm tt"))
|
diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Details.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Details.cshtml
index 990ad322f..b63376f7f 100644
--- a/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Details.cshtml
+++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Details.cshtml
@@ -83,7 +83,7 @@
@text
}
-
@Html.DateTime(commentEntry.Comment.CommentDateUtc.GetValueOrDefault()) |
+
@Display.DateTime(DateTimeUtc: commentEntry.Comment.CommentDateUtc.GetValueOrDefault()) |
-
diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml
index 1c198ee97..3e8fba850 100644
--- a/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml
+++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml
@@ -77,7 +77,7 @@
|
@* would ideally have permalinks for individual comments *@
-
+
@if (commentEntry.Comment.CommentText != null) {
var ellipsized = Html.Ellipsize(commentEntry.Comment.CommentText, 500);
var paragraphed = new HtmlString(ellipsized.ToHtmlString().Replace("\r\n", ""));
diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.SummaryAdmin.cshtml
index 1eb13bfe2..4ed1d302e 100644
--- a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.SummaryAdmin.cshtml
+++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.SummaryAdmin.cshtml
@@ -30,7 +30,7 @@
}
else {
@T("Scheduled")
- @Html.DateTime(((DateTime?)Model.ScheduledPublishUtc).Value.ToLocalTime(), T("M/d/yyyy h:mm tt"))
+ @Display.DateTime(((DateTime?)Model.ScheduledPublishUtc).Value.ToLocalTime(), T("M/d/yyyy h:mm tt"))
} |
}
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Setup/SetupMode.cs b/src/Orchard.Web/Modules/Orchard.Setup/SetupMode.cs
index 4db4bc375..e33154734 100644
--- a/src/Orchard.Web/Modules/Orchard.Setup/SetupMode.cs
+++ b/src/Orchard.Web/Modules/Orchard.Setup/SetupMode.cs
@@ -188,6 +188,10 @@ namespace Orchard.Setup {
public string BaseUrl {
get { return ""; }
}
+
+ public string SiteTimeZone {
+ get { return TimeZoneInfo.Local.Id; }
+ }
}
}
}
diff --git a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs
index 9750c0c7c..90d4140f5 100644
--- a/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs
+++ b/src/Orchard/Mvc/Html/HtmlHelperExtensions.cs
@@ -165,28 +165,6 @@ namespace Orchard.Mvc.Html {
#endregion
- #region Format Date/Time
-
- public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime? value, LocalizedString defaultIfNull) {
- return value.HasValue ? htmlHelper.DateTime(value.Value) : defaultIfNull;
- }
-
- public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime? value, LocalizedString defaultIfNull, LocalizedString customFormat) {
- return value.HasValue ? htmlHelper.DateTime(value.Value, customFormat) : defaultIfNull;
- }
-
- public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime value) {
- //TODO: (erikpo) This default format should come from a site setting
- return htmlHelper.DateTime(value.ToLocalTime(), new LocalizedString("MMM d yyyy h:mm tt")); //todo: above comment and get rid of just wrapping this as a localized string
- }
-
- public static LocalizedString DateTime(this HtmlHelper htmlHelper, DateTime value, LocalizedString customFormat) {
- //TODO: (erikpo) In the future, convert this to "local" time before calling ToString
- return new LocalizedString(value.ToString(customFormat.Text));
- }
-
- #endregion
-
#region Image
public static MvcHtmlString Image(this HtmlHelper htmlHelper, string src, string alt, object htmlAttributes) {
diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj
index 30d07d3c2..d42e28f4e 100644
--- a/src/Orchard/Orchard.Framework.csproj
+++ b/src/Orchard/Orchard.Framework.csproj
@@ -276,10 +276,16 @@
+
+
+
+
+
+
@@ -884,7 +890,7 @@
-
+
diff --git a/src/Orchard/Services/Clock.cs b/src/Orchard/Services/Clock.cs
index e72f7fae1..692768617 100644
--- a/src/Orchard/Services/Clock.cs
+++ b/src/Orchard/Services/Clock.cs
@@ -2,20 +2,6 @@
using Orchard.Caching;
namespace Orchard.Services {
- public interface IClock : IVolatileProvider {
- DateTime UtcNow { get; }
-
- ///
- /// Each retrieved value is cached during the specified amount of time.
- ///
- IVolatileToken When(TimeSpan duration);
-
- ///
- /// The cache is active until the specified time. Each subsequent access won't be cached.
- ///
- IVolatileToken WhenUtc(DateTime absoluteUtc);
- }
-
public class Clock : IClock {
public DateTime UtcNow {
get { return DateTime.UtcNow; }
diff --git a/src/Orchard/Services/IClock.cs b/src/Orchard/Services/IClock.cs
new file mode 100644
index 000000000..3560a9318
--- /dev/null
+++ b/src/Orchard/Services/IClock.cs
@@ -0,0 +1,56 @@
+using System;
+using Orchard.Caching;
+
+namespace Orchard.Services {
+ ///
+ /// Provides the current Utc , and time related method for cache management.
+ /// This service should be used whenever the current date and time are needed, instead of directly.
+ /// It also makes implementations more testable, as time can be mocked.
+ ///
+ public interface IClock : IVolatileProvider {
+ ///
+ /// Gets the current of the system, expressed in Utc
+ ///
+ DateTime UtcNow { get; }
+
+ ///
+ /// Provides a instance which can be used to cache some information for a
+ /// specific duration.
+ ///
+ /// The duration that the token must be valid.
+ ///
+ /// This sample shows how to use the method by returning the result of
+ /// a method named LoadVotes(), which is computed every 10 minutes only.
+ ///
+ /// _cacheManager.Get("votes",
+ /// ctx => {
+ /// ctx.Monitor(_clock.When(TimeSpan.FromMinutes(10)));
+ /// return LoadVotes();
+ /// });
+ ///
+ ///
+ IVolatileToken When(TimeSpan duration);
+
+ ///
+ /// Provides a instance which can be used to cache some
+ /// until a specific date and time.
+ ///
+ /// The date and time that the token must be valid until.
+ ///
+ /// This sample shows how to use the method by returning the result of
+ /// a method named LoadVotes(), which is computed once, and no more until the end of the year.
+ ///
+ /// var endOfYear = _clock.UtcNow;
+ /// endOfYear.Month = 12;
+ /// endOfYear.Day = 31;
+ ///
+ /// _cacheManager.Get("votes",
+ /// ctx => {
+ /// ctx.Monitor(_clock.WhenUtc(endOfYear));
+ /// return LoadVotes();
+ /// });
+ ///
+ ///
+ IVolatileToken WhenUtc(DateTime absoluteUtc);
+ }
+}
diff --git a/src/Orchard/Settings/ISite.cs b/src/Orchard/Settings/ISite.cs
index e37d47e63..666a58f46 100644
--- a/src/Orchard/Settings/ISite.cs
+++ b/src/Orchard/Settings/ISite.cs
@@ -1,4 +1,5 @@
-using Orchard.ContentManagement;
+using System;
+using Orchard.ContentManagement;
namespace Orchard.Settings {
///
@@ -14,5 +15,6 @@ namespace Orchard.Settings {
ResourceDebugMode ResourceDebugMode { get; set; }
int PageSize { get; set; }
string BaseUrl { get; }
+ string SiteTimeZone { get; }
}
}
diff --git a/src/Orchard/Time/CurrentTimeZoneWorkContext.cs b/src/Orchard/Time/CurrentTimeZoneWorkContext.cs
new file mode 100644
index 000000000..8951ea2b7
--- /dev/null
+++ b/src/Orchard/Time/CurrentTimeZoneWorkContext.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace Orchard.Time {
+ public class CurrentTimeZoneWorkContext : IWorkContextStateProvider {
+ private readonly IEnumerable _timeZoneSelectors;
+
+ public CurrentTimeZoneWorkContext(IEnumerable timeZoneSelectors) {
+ _timeZoneSelectors = timeZoneSelectors;
+ }
+
+ public Func Get(string name) {
+ if (name == "CurrentTimeZone") {
+ return ctx => (T)(object)CurrentTimeZone(ctx.HttpContext);
+ }
+ return null;
+ }
+
+ TimeZoneInfo CurrentTimeZone(HttpContextBase httpContext) {
+ var timeZone = _timeZoneSelectors
+ .Select(x => x.GetTimeZone(httpContext))
+ .Where(x => x != null)
+ .OrderByDescending(x => x.Priority)
+ .FirstOrDefault();
+
+ if (timeZone == null) {
+ return null;
+ }
+
+ return timeZone.TimeZone;
+ }
+ }
+}
diff --git a/src/Orchard/Time/FallbackTimeZoneSelector.cs b/src/Orchard/Time/FallbackTimeZoneSelector.cs
new file mode 100644
index 000000000..180bb3e37
--- /dev/null
+++ b/src/Orchard/Time/FallbackTimeZoneSelector.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Web;
+
+namespace Orchard.Time {
+ ///
+ /// Implements by providing the timezone defined in the machine's local settings.
+ ///
+ public class FallbackTimeZoneSelector : ITimeZoneSelector {
+ public TimeZoneSelectorResult GetTimeZone(HttpContextBase context) {
+ return new TimeZoneSelectorResult {
+ Priority = -100,
+ TimeZone = TimeZoneInfo.Local
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Orchard/Time/ITimeZoneSelector.cs b/src/Orchard/Time/ITimeZoneSelector.cs
new file mode 100644
index 000000000..ce341ecda
--- /dev/null
+++ b/src/Orchard/Time/ITimeZoneSelector.cs
@@ -0,0 +1,7 @@
+using System.Web;
+
+namespace Orchard.Time {
+ public interface ITimeZoneSelector : IDependency {
+ TimeZoneSelectorResult GetTimeZone(HttpContextBase context);
+ }
+}
diff --git a/src/Orchard/Time/SiteTimeZoneSelector.cs b/src/Orchard/Time/SiteTimeZoneSelector.cs
new file mode 100644
index 000000000..300d5548e
--- /dev/null
+++ b/src/Orchard/Time/SiteTimeZoneSelector.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Web;
+
+namespace Orchard.Time {
+ ///
+ /// Implements by providing the timezone defined in the sites settings.
+ ///
+ public class SiteTimeZoneSelector : ITimeZoneSelector {
+ private readonly IWorkContextAccessor _workContextAccessor;
+
+ public SiteTimeZoneSelector(IWorkContextAccessor workContextAccessor) {
+ _workContextAccessor = workContextAccessor;
+ }
+
+ public TimeZoneSelectorResult GetTimeZone(HttpContextBase context) {
+ var siteTimeZoneId = _workContextAccessor.GetContext(context).CurrentSite.SiteTimeZone;
+
+ if (String.IsNullOrEmpty(siteTimeZoneId)) {
+ return null;
+ }
+
+ return new TimeZoneSelectorResult {
+ Priority = -5,
+ TimeZone = TimeZoneInfo.FindSystemTimeZoneById(siteTimeZoneId)
+ };
+ }
+ }
+}
diff --git a/src/Orchard/Time/TimeZoneSelectorResult.cs b/src/Orchard/Time/TimeZoneSelectorResult.cs
new file mode 100644
index 000000000..3a34731a0
--- /dev/null
+++ b/src/Orchard/Time/TimeZoneSelectorResult.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Orchard.Time {
+ public class TimeZoneSelectorResult {
+ public int Priority { get; set; }
+ public TimeZoneInfo TimeZone { get; set; }
+ }
+}
diff --git a/src/Orchard/WorkContext.cs b/src/Orchard/WorkContext.cs
index e5b5f1540..28910debe 100644
--- a/src/Orchard/WorkContext.cs
+++ b/src/Orchard/WorkContext.cs
@@ -1,4 +1,5 @@
-using System.Web;
+using System;
+using System.Web;
using Orchard.Environment.Extensions.Models;
using Orchard.Security;
using Orchard.Settings;
@@ -75,5 +76,13 @@ namespace Orchard {
get { return GetState("CurrentCulture"); }
set { SetState("CurrentCulture", value); }
}
+
+ ///
+ /// Time zone of the work context
+ ///
+ public TimeZoneInfo CurrentTimeZone {
+ get { return GetState("CurrentTimeZone"); }
+ set { SetState("CurrentTimeZone", value); }
+ }
}
}
|