2011-11-19 39 views
27

Estoy construyendo una aplicación en mvc3 y quiero hacer eso cuando el usuario entra en mi sitio quiero saber que es el usuario zona horaria. Quiero saber cómo hacer esto en C# no en script java?Cómo obtener la zona horaria actual del usuario en C#

+0

Publicación relacionada: http://stackoverflow.com/questions/338482/can-you-determine-timezone-from-request-variables – adatapost

Respuesta

18

Esto no es posible desde el lado del servidor a menos que lo asuma a través de la dirección IP de los usuarios o haga que el usuario lo configure en algún perfil. Puede obtener el tiempo de los clientes a través de javascript.

Vea aquí la solución javacript: Getting the client's timezone in JavaScript

6

que tiene el mismo problema, por desgracia no hay manera para que el servidor conozca la zona horaria del cliente. Si lo desea, puede enviar la zona horaria del cliente como encabezado mientras realiza una llamada ajax.

En caso si usted desea más información sobre cómo añadir la cabecera de este post puede ayudar a cómo agregar encabezado de solicitud: How can I add a custom HTTP header to ajax request with js or jQuery?

new Date().getTimezoneOffset();//gets the timezone offset 

Si no desea agregar cabecera cada vez, se puede pensar de configurar una cookie desde que se envía la cookie con httpRequest puede procesar la cookie para obtener la zona horaria del cliente en el servidor. Pero no prefiero agregar cookies, por la misma razón que enviaron con todas las solicitudes http. Gracias.

+1

Poner la zona horaria en una cookie es una excelente alternativa para cuando no desea utilizar ajax solicita esto, además usted no tiene que usar JavaScript para mostrar una fecha, solo para configurar la cookie. –

+0

@RuudLenders pero necesita javascript para establecer la cookie una vez – edc65

13

Como se ha mencionado, es necesario que su cliente para contar sus datos de servidor ASP.NET sobre el que la zona horaria que se encuentran.

He aquí un ejemplo.

Tengo un controlador angular, que carga una lista de registros de mi base de datos de SQL Server en formato JSON. El problema es que los valores DateTime en estos registros están en la zona horaria UTC, y quiero mostrarle al usuario la fecha/hora en su zona horaria local.

determino la zona horaria del usuario (en minutos) utilizando la función "getTimezoneOffset()" JavaScript, tiene que poner este valor a la dirección URL del servicio JSON Estoy intentando llamar:

$scope.loadSomeDatabaseRecords = function() { 

    var d = new Date() 
    var timezoneOffset = d.getTimezoneOffset(); 

    return $http({ 
     url: '/JSON/LoadSomeJSONRecords.aspx?timezoneOffset=' + timezoneOffset, 
     method: 'GET', 
     async: true, 
     cache: false, 
     headers: { 'Accept': 'application/json', 'Pragma': 'no-cache' } 
    }).success(function (data) { 
     $scope.listScheduleLog = data.Results; 
    }); 
} 

En mi ASP. código de red, me extraer el parámetro timezoneOffset ...

int timezoneOffset = 0; 

string timezoneStr = Request["timezoneOffset"]; 
if (!string.IsNullOrEmpty(timezoneStr)) 
    int.TryParse(timezoneStr, out timezoneOffset); 

LoadDatabaseRecords(timezoneOffset); 

... y pasarlo a la función que carga los registros de la base de datos.

Es un poco complicado ya que quiero llamar a mi C# FromUTCData función en cada registro de la base de datos, pero LINQ a SQL No se pueden combinar SQL crudo con funciones de C#.

La solución es leer primero en los registros, luego repetirlos, aplicando el desplazamiento de la zona horaria a los campos DateTime en cada registro.

public var LoadDatabaseRecords(int timezoneOffset) 
{ 
    MyDatabaseDataContext dc = new MyDatabaseDataContext(); 

    List<MyDatabaseRecords> ListOfRecords = dc.MyDatabaseRecords.ToList(); 

    var results = (from OneRecord in ListOfRecords 
      select new 
      { 
       ID = OneRecord.Log_ID, 
       Message = OneRecord.Log_Message, 
       StartTime = FromUTCData(OneRecord.Log_Start_Time, timezoneOffset), 
       EndTime = FromUTCData(OneRecord.Log_End_Time, timezoneOffset) 
      }).ToList(); 

    return results; 
} 

public static DateTime? FromUTCData(DateTime? dt, int timezoneOffset) 
{ 
    // Convert a DateTime (which might be null) from UTC timezone 
    // into the user's timezone. 
    if (dt == null) 
     return null; 

    DateTime newDate = dt.Value - new TimeSpan(timezoneOffset/60, timezoneOffset % 60, 0); 
    return newDate; 
} 

funciona muy bien, sin embargo, y este código es muy útil cuando se escriben un servicio web para mostrar fecha/veces para los usuarios en diferentes partes del mundo.

En este momento, estoy escribiendo este artículo a las 11:00 a.m. hora de Zurich, pero si lo leyeras en Los Ángeles, verás que lo edité a las 2 a.m. (hora local). Con un código como este, puede hacer que sus páginas web muestren los horarios que tienen sentido para los usuarios internacionales de su sitio web.

Phew.

Espero que esto ayude.

+2

Gracias Mike. Me di cuenta de que puedes hacer 'new TimeSpan (0, timezoneOffset, 0)' y calcula correctamente el número de horas. – lsibaja

+0

a mi entender que no funciona debido a DST – Giedrius

+0

DST no debería importar. Su JavaScript tendrá esto en cuenta cuando llame a "getTimezoneOffset()". Lo único que importa es que, en el servidor, DateTimes está * siempre * basado en UTC, y en el cliente, estamos aprobando correctamente el desplazamiento de la zona horaria. –

3

Sé que el usuario preguntó acerca de una solución que no es javascript, pero quería publicar una solución javascript que se me ocurrió. Encontré algunas bibliotecas js (jsTimezoneDetect, momentjs), pero su resultado fue un código IANA, que no pareció ayudarme a obtener un objeto TimeZoneInfo en C#. Tomé prestadas ideas de jsTimezoneDetect. En javascript, obtengo el BaseUtcOffset y el primer día de DST y lo envío al servidor. El servidor luego lo convierte en un objeto TimeZoneInfo.

Ahora mismo no me importa si la Zona horaria del cliente se elige como "Hora del Pacífico (EE. UU.)" O "Baja California" por ejemplo, ya que cualquiera creará las conversiones de hora correctas (creo). Si encuentro varias coincidencias, actualmente solo elijo la primera coincidencia TimeZoneInfo encontrada.

A continuación, puedo convertir mis fechas UTC partir de la base de datos a la hora local:

DateTime clientDate = TimeZoneInfo.ConvertTimeFromUtc(utcDate, timeZoneInfo); 

Javascript

// Time zone. Sets two form values: 
// tzBaseUtcOffset: minutes from UTC (non-DST) 
// tzDstDayOffset: number of days from 1/1/2016 until first day of DST ; 0 = no DST 
var form = document.forms[0]; 
var janOffset = -new Date(2016, 0, 1).getTimezoneOffset();  // Jan 
var julOffset = -new Date(2016, 6, 1).getTimezoneOffset();  // Jul 
var baseUtcOffset = Math.min(janOffset, julOffset);    // non DST offset (winter offset) 
form.elements["tzBaseUtcOffset"].value = baseUtcOffset; 
// Find first day of DST (from 1/1/2016) 
var dstDayOffset = 0; 
if (janOffset != julOffset) { 
    var startDay = janOffset > baseUtcOffset ? 180 : 0; // if southern hemisphere, start 180 days into year 
    for (var day = startDay; day < 365; day++) if (-new Date(2016, 0, day + 1, 12).getTimezoneOffset() > baseUtcOffset) { dstDayOffset = day; break; } // noon 
} 
form.elements["tzDstDayOffset"].value = dstDayOffset; 

C#

private TimeZoneInfo GetTimeZoneInfo(int baseUtcOffset, int dstDayOffset) { 

     // Converts client/browser data to TimeZoneInfo 
     // baseUtcOffset: minutes from UTC (non-DST) 
     // dstDayOffset: number of days from 1/1/2016 until first day of DST ; 0 = no DST 
     // Returns first zone info that matches input, or server zone if none found 

     List<TimeZoneInfo> zoneInfoArray = new List<TimeZoneInfo>(); // hold multiple matches 
     TimeSpan timeSpan = new TimeSpan(baseUtcOffset/60, baseUtcOffset % 60, 0); 
     bool supportsDst = dstDayOffset != 0; 
     foreach (TimeZoneInfo zoneInfo in TimeZoneInfo.GetSystemTimeZones()) { 
      if (zoneInfo.BaseUtcOffset.Equals(timeSpan) && zoneInfo.SupportsDaylightSavingTime == supportsDst) { 
       if (!supportsDst) zoneInfoArray.Add(zoneInfo); 
       else { 
        // Has DST. Find first day of DST and test for match with sent value. Day = day offset into year 
        int foundDay = 0; 
        DateTime janDate = new DateTime(2016, 1, 1, 12, 0, 0); // noon 
        int startDay = zoneInfo.IsDaylightSavingTime(janDate) ? 180 : 0; // if southern hemsphere, start 180 days into year 
        for (int day = startDay; day < 365; day++) if (zoneInfo.IsDaylightSavingTime(janDate.AddDays(day))) { foundDay = day; break; } 
        if (foundDay == dstDayOffset) zoneInfoArray.Add(zoneInfo); 
       } 
      } 
     } 
     if (zoneInfoArray.Count == 0) return TimeZoneInfo.Local; 
     else return zoneInfoArray[0]; 
    } 
0

Para Dot Net versión 3.5 y superior que pueda uso:

TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow); 

pero para la red del punto bajo la versión 3.5 se puede manejar manualmente a través de la siguiente manera:

En primer lugar obtener desplazada de cliente y almacenarlo en la galleta

function setTimezoneCookie(){ 

var timezone_cookie = "timezoneoffset"; 

// if the timezone cookie not exists create one. 
if (!$.cookie(timezone_cookie)) { 

    // check if the browser supports cookie 
    var test_cookie = 'test cookie'; 
    $.cookie(test_cookie, true); 

    // browser supports cookie 
    if ($.cookie(test_cookie)) { 

     // delete the test cookie 
     $.cookie(test_cookie, null); 

     // create a new cookie 
     $.cookie(timezone_cookie, new Date().getTimezoneOffset()); 

     // re-load the page 
     location.reload(); 
    } 
} 
// if the current timezone and the one stored in cookie are different 
// then store the new timezone in the cookie and refresh the page. 
else {   

    var storedOffset = parseInt($.cookie(timezone_cookie)); 
    var currentOffset = new Date().getTimezoneOffset(); 

    // user may have changed the timezone 
    if (storedOffset !== currentOffset) { 
     $.cookie(timezone_cookie, new Date().getTimezoneOffset()); 
     location.reload(); 
    } 
} 

}

después de que pueda utilizar cookies en código de fondo de esa manera:

public static string ToClientTime(this DateTime dt) 
{ 
    // read the value from session 
    var timeOffSet = HttpContext.Current.Session["timezoneoffset"]; 

    if (timeOffSet != null) 
    { 
     var offset = int.Parse(timeOffSet.ToString()); 
     dt = dt.AddMinutes(-1 * offset); 

     return dt.ToString(); 
    } 

    // if there is no offset in session return the datetime in server timezone 
    return dt.ToLocalTime().ToString(); 
} 
-1
System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_TIMEZONE"] ; 
+2

¿Podría proporcionar una referencia a esta información? Un fragmento de código sin contexto no es muy valioso. – axlj

Cuestiones relacionadas