开发者

Display DateTime in GridView using user's time

I have a DateTime stored in UTC time that I'd like to display to the user in their local time from within a GridView control. How can I convert my DateTime to the user's time (not my server's local time)? Here is my current field as it appears开发者_StackOverflow社区 in the GridView Columns collection:

<asp:BoundField DataField="RunTime" HeaderText="Run Time"
  SortExpression="RunTime" DataFormatString="{0:f}" />


You would need to know the user's time zone - for example, from profile or user data your website keeps. Alternatively, you can try to guestimate based on GeoIP data, although that can be suspect because the user may not be using that particular time zone on their computer.

.NET does not automatically know what time the user is using on the remote end.


For my site I just used jQuery to do an AJAX request to a timezone HTTP handler that would record the timezone in session, then I created an extension method "ToVisitorTime" that would use this value.

In your base template or page header:

<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>

Then to hide it if you already grabbed the session, in the codebehind:

protected void Page_Load(object sender, EventArgs e)
{
    object sessOffset = Session["OFFSET"];

    if (sessOffset == null)
    {
        plcTimezoneScript.Visible = true;
    }
}

For the /ajax/TimezoneOffset.ashx handler:

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;
        }
    }

}

Then an extension method to take care of showing the right time (returns a DateTime object for further processing if need be). Remember to store this in a static class:

    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;
}

This was taken from a tutorial I've yet to publish but should do what you need. One downside is that on the first page load, nothing will be in the correct time.

You should use a JS method probably, considering this already requires JS to work. I would recommend the Datejs plugin and use some jQuery to automatically replace utc dates.


You can use JavaScript to find the user's timezone:

var userTime =(new Date().getTimezoneOffset()/60)*(-1);

Then, store this in a hidden field or pass it along as a parameter. In your page, you'll have to override the GridView's RowDataBound event, find the time and convert it using DateTime's conversion methods.

edit: Probably the safest way to do this is to have the user store their timezone in a profile. That way, turning off JavaScript won't affect your application.

edit: Server-side code

    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);
    }

See: http://msdn.microsoft.com/en-us/library/system.timezone(VS.90).aspx


you best bet would be to store the user's preference of time zone. You can't correctly guess the time zone from the browser info.

here's a quick tutorial to store the selected timezone in Session, and create a quick control that can be on every page to update the printed dates.

http://www.dotnet-friends.com/articles/asp/artinasp381efae4-87c8-41ae-9427-2ae75edd9594.aspx


You can send timezone name to the server using Intl.DateTimeFormat().resolvedOptions().timeZone (supported in all modern browsers) and perform approp timezone conversions there.

For something common like this, I thought ASP.NET would have an inherent and clean way to do this!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜