Как получить текущий часовой пояс пользователя в C # - PullRequest
32 голосов
/ 19 ноября 2011

Я создаю приложение в MVC3, и когда пользователь заходит на мой сайт, я хочу знать часовой пояс этого пользователя.Я хочу знать, как сделать это в C # не в javaScript?

Ответы [ 7 ]

19 голосов
/ 28 мая 2015

Как уже упоминалось, ваш клиент должен сообщить вашему серверу ASP.Net подробности о том, в каком часовом поясе он находится.

Вот пример.

У меня есть контроллер Angular,который загружает список записей из моей базы данных SQL Server в формате JSON.Проблема в том, что значения DateTime в этих записях находятся в часовом поясе UTC, и я хочу показать пользователю дату / время в их местном часовом поясе.

Я определяю часовой пояс пользователя (в минутах) с помощью функции JavaScript "getTimezoneOffset()", затем добавляю это значение к URL-адресу службы JSON, которую я пытаюсь вызвать:

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

В своем коде ASP.Net я извлекаю параметр timezoneOffset ...

int timezoneOffset = 0;

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

LoadDatabaseRecords(timezoneOffset);

... и передаю его в мою функцию, которая загружает записи из базы данных.

Это немного грязно, так как я хочу вызывать свою функцию C # FromUTCData для каждой записи из базы данных, но LINQ to SQL не может объединить сырой SQL с функциями C #.

Решение состоит в том, чтобы сначала прочитать записи, а затем выполнить итерацию по ним, применяя смещение часового пояса к полям DateTime в каждой записи.

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

Это работает хорошо, хотяэтот код действительно полезен при написании веб-сервиса для отображения даты / времени пользователям в разных частях света.

Прямо сейчас я пишу эту статью в 11:00 по Цюрихскому времени, но если вы ее читалив Лос-Анджелесе вы увидите, что я редактировал его в 2 часа ночи (по местному времени).Используя такой код, вы можете заставить свои веб-страницы показывать время, которое имеет смысл для иностранных пользователей вашего сайта.

Фу.

Надеюсь, это поможет.

19 голосов
/ 19 ноября 2011

Это невозможно на стороне сервера, если вы не примете это через IP-адрес пользователя или не попросите пользователя установить его в какой-либо форме профиля.Вы можете узнать время клиентов через javascript.

См. Здесь решение для javacript: Получение часового пояса клиента в JavaScript

6 голосов
/ 22 сентября 2014

У меня возникла та же проблема. К сожалению, сервер не может узнать часовой пояс клиента.Если вы хотите, вы можете отправить часовой пояс клиента в качестве заголовка во время вызова ajax.

В случае, если вам нужна дополнительная информация о добавлении заголовка, этот пост может помочь, как добавить заголовок к запросу: Как добавить пользовательский заголовок HTTP в запрос ajax с помощью js или jQuery?

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

Если вы не хотите каждый раз добавлять заголовок, вы можете подумать о настройке cookie-файла, поскольку cookie-файл отправляется вместе со всем httpRequest, который вы можете обработать cookie-файлом, чтобы получить часовой пояс клиента на стороне сервера.Но я не предпочитаю добавлять куки, по той же причине, по которой они отправляются со всеми http-запросами.Спасибо.

3 голосов
/ 26 июня 2016

Я знаю, что пользователь спросил о решении, не поддерживающем javascript, но я хотел опубликовать решение javascript, которое придумал. Я нашел несколько библиотек js (jsTimezoneDetect, momentjs), но их результатом был код IANA, который, похоже, не помог мне с получением объекта TimeZoneInfo в C #. Я позаимствовал идеи от jsTimezoneDetect. В javascript я получаю BaseUtcOffset и первый день DST и отправляю на сервер. Затем сервер преобразует это в объект TimeZoneInfo.

Сейчас мне все равно, выбран ли часовой пояс клиента, например, "Тихоокеанское время (США)" или "Нижняя Калифорния", поскольку любой из них создаст правильные преобразования времени (я думаю). Если я нахожу несколько совпадений, я просто выбираю первое найденное совпадение TimeZoneInfo.

Затем я могу преобразовать свои даты UTC из базы данных в местное время:

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];
    }
1 голос
/ 28 января 2019

Вам нужно будет использовать как клиентские, так и серверные технологии.

На стороне клиента:
(выберите один)

  • Это работает в большинстве современных браузеров:

    Intl.DateTimeFormat().resolvedOptions().timeZone
    
  • Существует также jsTimeZoneDetect jstz.determine() или Moment-Timezone moment.tz.guess() для старых браузеров.

Результатом любого из них будет идентификатор часового пояса IANA , например America/Los_Angeles. Отправьте этот результат на сервер любым удобным для вас способом.

На стороне сервера:
(выберите один)

  • Использование TimeZoneInfo (только в системах, отличных от Windows):

    TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
    
  • Использование TimeZoneConverter (в любой ОС):

    TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("America/New_York");
    
  • Использование NodaTime (в любой ОС):

    DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
    
0 голосов
/ 09 марта 2018
System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_TIMEZONE"] ;
0 голосов
/ 12 декабря 2017

Для Dot Net версии 3.5 и выше вы можете использовать:

TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);

, но для Dot Net В версии 3.5 вы можете обрабатывать это вручную следующим образом:

сначала получить смещение от клиентаи сохранить его в cookie

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

}

, после чего вы можете использовать cookie в бэкэнд-коде так:

   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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...