Display DateTime in GridView using custom time

I have a DateTime stored in UTC that I would like to show to the user at their local time from within a GridView control. How can I convert DateTime to user time (not my server time)? Here is my current field that appears in the GridView Columns collection:

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

      

+2


a source to share


4 answers


You need to know the user's time zone - for example, from profiles or user data stored on your website. Alternatively, you can try in guest mode based on GeoIP data, although this might be suspicious as the user might not be using that particular time zone on their computer.



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

+3


a source


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

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

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

edit: Probably the safest way to do this is to store a custom timezone in the profile. This way, turning off JavaScript will not affect your application.



edit: Server 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

+3


a source


For my site, I just used jQuery to make an AJAX request to the HTTP time handler that was recording the timezone in the session, then I created an extension method ToVisitorTime that will use that value.

In the 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've already grabbed the session, in code:

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 add an extension method to take care of showing the correct time (returns a DateTime object if necessary for further processing). Remember to keep 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 haven't posted yet, but should do what you need. One drawback is that when the first page loads, nothing will happen at the right time.

You should be using a JS method, probably given that it already requires JS to work. I would recommend the Datejs plugin and use some jQuery to automatically replace utc dates.

+3


a source


the best would be to keep the user's preference for the timezone. You cannot correctly guess the timezone from the browser information.

here's a quick tutorial for storing a selected timezone in a session and creating a quick control that can be on every page to update printed dates.

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

+2


a source







All Articles