我有一个以UTC时间存储的DateTime,我希望在GridView控件中以本地时间显示给用户。如何将DateTime转换为用户的时间(而不是我服务器的本地时间)?这是我在GridView Columns集合中出现的当前字段:
<asp:BoundField DataField="RunTime" HeaderText="Run Time"
SortExpression="RunTime" DataFormatString="{0:f}" />
答案 0 :(得分:3)
您需要知道用户的时区 - 例如,您的网站所保存的个人资料或用户数据。或者,您可以尝试根据GeoIP数据进行猜测,尽管这可能是可疑的,因为用户可能没有在他们的计算机上使用该特定时区。
.NET不会自动知道用户在远程端使用的时间。
答案 1 :(得分:3)
您可以使用JavaScript查找用户的时区:
var userTime =(new Date().getTimezoneOffset()/60)*(-1);
然后,将其存储在隐藏字段中或作为参数传递。在你的页面中,你必须覆盖GridView的RowDataBound事件,找到时间并使用DateTime的转换方法进行转换。
编辑: 可能最安全的方法是让用户将他们的时区存储在配置文件中。这样,关闭JavaScript不会影响您的应用程序。
编辑: 服务器端代码
static void Main()
{
const string timeFmt = "{0,-30}{1:yyyy-MM-dd HH:mm}";
DateTime dt = DateTime.Now.ToUniversalTime();
for (int i = -12; i <= 12; i++)
{
DateTime converted = ConvertToLocalDateTime(dt, i);
Console.WriteLine(timeFmt, "Offset: " + i , converted);
}
Console.ReadLine();
}
static DateTime ConvertToLocalDateTime(DateTime dateTime, int offset)
{
TimeZoneInfo destinationTimeZone = TimeZoneInfo.GetSystemTimeZones()
.Where(x => x.BaseUtcOffset.Hours.Equals(offset)).FirstOrDefault();
var rule = destinationTimeZone.GetAdjustmentRules().Where(x =>
x.DateStart <= dateTime && dateTime <= x.DateEnd)
.FirstOrDefault();
TimeSpan baseOffset = TimeSpan.Zero;
if(rule != null)
{
baseOffset -= destinationTimeZone.IsDaylightSavingTime(dateTime) ?
rule.DaylightDelta : TimeSpan.Zero;
}
DateTimeOffset dto = DateTimeOffset.Parse(dateTime.ToString());
return new DateTime(TimeZoneInfo.ConvertTimeFromUtc(dateTime, destinationTimeZone).Ticks + baseOffset.Ticks);
}
请参阅:http://msdn.microsoft.com/en-us/library/system.timezone(VS.90).aspx
答案 2 :(得分:3)
对于我的网站,我只是使用jQuery对时区HTTP处理程序执行AJAX请求,该处理程序将在会话中记录时区,然后我创建了一个使用此值的扩展方法“ToVisitorTime”。
在基本模板或页眉中:
<script type="text/javascript" src="/lib/js/jquery.js"></script>
<asp:Placeholder id="plcTimezoneScript" Visible="false" runat="server">
<script type="text/javascript">
function getVisitorTimezone()
{
// get visitor timezone offset
var curDt = new Date();
$.post("/ajax/TimezoneOffset.ashx", {
offset: -(curDt.getTimezoneOffset()/60)
});
}
$(getVisitorTimezone);
</script>
</asp:Placeholder>
然后在代码隐藏中抓住会话时隐藏它:
protected void Page_Load(object sender, EventArgs e)
{
object sessOffset = Session["OFFSET"];
if (sessOffset == null)
{
plcTimezoneScript.Visible = true;
}
}
对于/ajax/TimezoneOffset.ashx处理程序:
using System;
using System.Web;
using System.Web.SessionState;
public class TimezoneOffset : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
object sessOffset = context.Session["OFFSET"];
if (context.Request.RequestType == "POST")
{
if (sessOffset == null)
{
string offset = context.Request.Form.Get("offset");
int Offset = 0;
if (!String.IsNullOrEmpty(offset)
&& Int32.TryParse(offset, out Offset))
{
context.Session.Add("OFFSET", Offset);
}
}
}
}
public bool IsReusable {
get {
return false;
}
}
}
然后是一个扩展方法来处理显示正确的时间(如果需要,返回DateTime对象以进行进一步处理)。请记住将其存储在静态类中:
public static DateTime ToVisitorTime(this DateTime UtcDate)
{
// use timezone offset, if set
object TimezoneOffset = HttpContext.Current.Session["OFFSET"];
if (TimezoneOffset != null)
{
int Offset = 0;
if (Int32.TryParse(TimezoneOffset.ToString(), out Offset))
{
UtcDate = UtcDate.AddHours(Offset);
}
else
{
UtcDate = UtcDate.ToLocalTime();
}
}
else
{
// well, at least show the local server time
UtcDate = UtcDate.ToLocalTime();
}
return UtcDate;
}
这是从我尚未发布的教程中获取的,但应该做你需要的。一个缺点是在第一页加载时,没有任何东西会在正确的时间内。
您可能应该使用JS方法,考虑到这已经需要JS才能工作。我建议使用Datejs插件并使用一些jQuery自动替换utc日期。
答案 3 :(得分:2)
您最好的选择是存储用户对时区的偏好。您无法从浏览器信息中正确猜出时区。
这是一个快速教程,用于在Session中存储选定的时区,并创建一个快速控件,可以在每个页面上更新打印日期。
http://www.dotnet-friends.com/articles/asp/artinasp381efae4-87c8-41ae-9427-2ae75edd9594.aspx
答案 4 :(得分:0)
您可以使用 Intl.DateTimeFormat().resolvedOptions().timeZone(所有现代浏览器都支持)将时区名称发送到服务器,并在那里执行适当的时区转换。
对于这种常见的事情,我认为 ASP.NET 会有一种固有且干净的方法来做到这一点!