如何在c#中获取当前用户时区
本文关键字:用户 时区 获取 | 更新日期: 2023-09-27 18:15:06
我正在MVC3中构建应用程序,当用户进入我的网站时,我想知道该用户的时区。我想知道如何在c#中而不是在javaScript中做到这一点?
如前所述,您需要您的客户端告诉您的ASP。. Net服务器的详细信息,他们在哪个时区。
下面是一个例子。
我有一个Angular控制器,它以JSON格式从我的SQL Server数据库加载记录列表。问题是,这些记录中的DateTime
值位于UTC时区,而我想向用户显示其本地时区的日期/时间。
我使用JavaScript"getTimezoneOffset()
"函数确定用户的时区(以分钟为单位),然后将此值附加到我试图调用的JSON服务的URL:
$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;
}
它工作得很好,当编写一个web服务向世界不同地区的用户显示日期/时间时,这段代码非常有用。
现在,我在苏黎世时间上午11点写这篇文章,但如果你在洛杉矶阅读,你会看到我在凌晨2点(当地时间)编辑它。使用这样的代码,你可以让你的网页显示对你网站的国际用户有意义的日期时间。
唷。
希望这对你有帮助。
这在服务器端是不可能的,除非您假定它是通过用户的ip地址或让用户在某种形式的配置文件中设置它。你可以通过javascript获取客户端的时间。
在JavaScript中获取客户机's时区您将需要同时使用客户端和服务器端技术。
客户端
(选择一个)
-
这适用于大多数现代浏览器:
Intl.DateTimeFormat().resolvedOptions().timeZone
-
还有jsTimeZoneDetect的
jstz.determine()
,或者Moment-Timezone的moment.tz.guess()
函数用于较旧的浏览器,尽管这些库通常只在较旧的应用程序中使用。
结果将是IANA时区标识符,如America/New_York
。将结果以您喜欢的任何方式发送到服务器。
服务器端:
(选择一个)
-
使用
TimeZoneInfo
(on。. NET 6+(适用于任何操作系统,或仅适用于非windows系统):TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
-
使用TimeZoneConverter(在任何操作系统):
TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("America/New_York");
-
使用nodeatime(在任何操作系统上):
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
我得到了同样的问题,不幸的是,服务器没有办法知道客户端的时区。如果你想,你可以发送客户端时区作为头,同时进行ajax调用。
在情况下,如果你想要更多的信息,在添加标题这篇文章可能有助于如何添加标题的请求:我怎么能添加一个自定义的HTTP头与js或jQuery ajax请求?
new Date().getTimezoneOffset();//gets the timezone offset
如果你不想每次都添加报头,你可以考虑设置一个cookie,因为cookie是与所有的httpRequest一起发送的,你可以处理cookie来获得服务器端的客户端时区。但我不喜欢添加cookie,出于同样的原因,他们发送与所有的http请求。谢谢。
对于Dot Net 3.5及更高版本,您可以使用:
TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);
但是对于3.5版本以下的Dot Net,您可以通过以下方式手动处理:
首先,从客户端获取Offset并将其存储在cookie 中。function setTimezoneCookie(){
var timezone_cookie = "timezoneoffset";
// if the timezone cookie does not exist 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();
}
我知道用户询问非javascript解决方案,但我想发布我想到的javascript解决方案。我发现了一些js库(jsTimezoneDetect, momentjs),但他们的输出是IANA代码,这似乎没有帮助我在c#中获得TimeZoneInfo对象。我借鉴了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];
}
您可以从客户端到服务器(任何web API调用)获取此信息
var timezoneOffset = new Date().getTimezoneOffset();
在timezoneoffset
细节的帮助下,您可以实现相同的目标。在这里,我的情况下,我转换UTC日期时间到我的客户端本地日期时间在服务器端。
DateTime clientDateTime = DateTime.UtcNow - new TimeSpan(timezoneOffset / 60, timezoneOffset % 60, 0);
点击查看代码示例
看看这个asp.net c#解决方案
TimeZoneInfo mytzone = TimeZoneInfo.Local;
System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_TIMEZONE"] ;