Как получить текущий часовой пояс пользователя в С#
Я создаю приложение в MVC3, и когда пользователь заходит на мой сайт, я хочу узнать его часовой пояс. Я хочу знать, как сделать это в С#, а не в javaScript?
Ответы
Ответ 1
Это не возможная сторона сервера, если вы не принимаете ее через IP-адрес пользователя или не устанавливаете ее в какой-либо форме профиля. Вы можете получить время клиентов через javascript.
См. здесь решение javacript: Получение часового пояса клиента в JavaScript
Ответ 2
Как уже упоминалось, вам нужен ваш клиент, чтобы сообщить вашим данным сервера 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);
... и передать его моей функции, которая загружает записи из базы данных.
Это немного беспорядочно, поскольку я хочу вызвать функцию С# FromUTCData
для каждой записи из базы данных, но LINQ to SQL не может комбинировать исходный SQL с функциями С#.
Решение состоит в том, чтобы сначала прочитать записи, а затем пропустить их, применяя смещение временной зоны к полям 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 timezone.
if (dt == null)
return null;
DateTime newDate = dt.Value - new TimeSpan(timezoneOffset / 60, timezoneOffset % 60, 0);
return newDate;
}
Это работает хорошо, и этот код действительно полезен при написании веб-службы для отображения даты/времени пользователям в разных частях мира.
Прямо сейчас, я пишу эту статью в 11 утра по Цюриху, но если вы читаете ее в Лос-Анджелесе, вы увидите, что я ее редактировал в 2 часа ночи (по местному времени). Используя такой код, вы можете заставить свои веб-страницы показывать даты, которые имеют смысл для международных пользователей вашего веб-сайта.
Уф.
Надеюсь, это поможет.
Ответ 3
У меня такая же проблема, но, к сожалению, сервер не знает часовой пояс клиента.
Если вы хотите, вы можете отправить часовой пояс клиента в качестве заголовка при вызове ajax.
В случае, если вам нужна дополнительная информация о добавлении заголовка, это сообщение может помочь добавить заголовок для запроса: Как добавить пользовательский заголовок HTTP в ajax-запрос с помощью js или JQuery?
new Date().getTimezoneOffset();//gets the timezone offset
Если вы не хотите добавлять заголовок каждый раз, вы можете подумать о настройке файла cookie, поскольку cookie отправляется со всем httpRequest, вы можете обработать файл cookie, чтобы получить часовой пояс клиента на стороне сервера. Но я не предпочитаю добавлять файлы cookie по той же причине, что и все HTTP-запросы.
Спасибо.
Ответ 4
Я знаю, что пользователь спросил о решении, отличном от javascript, но я хотел опубликовать решение javascript, которое я придумал. Я нашел несколько js-библиотек (jsTimezoneDetect, momentjs), но их вывод был кодом IANA, который, похоже, не помог мне получить объект TimeZoneInfo в С#. Я заимствовал идеи из jsTimezoneDetect. В javascript я получаю BaseUtcOffset и первый день DST и отправляю сервер. Затем сервер преобразует это в объект TimeZoneInfo.
В настоящее время меня не волнует, если клиентская часовая зона выбрана как "Pacific Time (США)" или "Baja California", например, либо создаст правильные преобразования времени (я думаю). Если я нахожу несколько совпадений, в настоящее время я просто выбираю первое найденное совпадение 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;
С#
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];
}
Ответ 5
Вам нужно будет использовать как клиентские, так и серверные технологии.
На стороне клиента:
(Выбери один)
-
Это работает в большинстве современных браузеров:
Intl.DateTimeFormat().resolvedOptions().timeZone
-
Для старых jstz.determine()
также есть jstz.determine()
jsTimeZoneDetect jstz.determine()
или Moment- moment.tz.guess()
.
Результатом любого из них будет идентификатор часового пояса IANA, например America/Los_Angeles
. Отправьте этот результат на сервер любым удобным для вас способом.
На стороне сервера:
(Выбери один)
-
Использование TimeZoneInfo
(только в системах, 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"];
Ответ 6
Для 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();
}
}
}
после этого вы можете использовать куки файл в этом коде:
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();
}
Ответ 7
Вы можете попробовать использовать приведенный ниже фрагмент...
var timeZone = $"{TimeZoneInfo.Local.StandardName} : {TimeZoneInfo.Local.DisplayName}";
Спасибо
Ответ 8
System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_TIMEZONE"] ;