C# 时间属性数据所涉及的时区转换解决方案
说明:开发一个可能跨国跨时区的云平台。其中,不同地区的用户访问平台时,所浏览的相关时间数据为当前地区所在的时区时间。
前提:平台所涉及到的时间属性所存储的数据需统一定义为UTC
或GMT
时间。
方案一:
-
前台处理:前台获取当前用户使用设备所在地区时区信息,并将相关时区信息设置在平台HTTP接口中,接口请求头添加请求参数如
User-Timezone
。 -
后台处理:后台自定义一个中间件或拦截器,对处理后的请求做时间转换逻辑操作,将返回接口中的所有时间参数值转换成当前用户所在地区时区时间,实现全局的时区转换功能。
方案二:
-
后台处理:后台接口正常返回时间数据,即UTC时间,不做时区转换处理。
-
前台处理:前台获取当前用户所在时区,对接口所返回的时间属性进行时区转换操作。
方案一实现过程
using System.Collections;
namespace Microsoft.AspNetCore.Mvc.Filters
{
public class UserTimeZoneFilter : IActionFilter, ITransientDependency
{
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Result is ObjectResult objectResult && objectResult.Value != null)
{
if (context.HttpContext.Request.Headers.TryGetValue("User-Timezone", out var timeZoneId))
{
var _timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
ConvertTimeProperties(objectResult.Value, _timeZoneInfo);
}
}
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
private void ConvertTimeProperties(object obj, TimeZoneInfo timeZoneInfo)
{
if (obj is IEnumerable enumerable)
{
// 处理数组中对象的时间属性转换
foreach (var item in enumerable)
{
ConvertTimeProperties(item, timeZoneInfo);
}
}
else
{
var properties = obj.GetType().GetProperties();
foreach (var property in properties)
{
if (IsDateTimeProperty(property))
{
var value = (DateTime)property.GetValue(obj);
if (value.Kind == DateTimeKind.Unspecified)
{
var convertedValue = TimeZoneInfo.ConvertTime(value, timeZoneInfo);
property.SetValue(obj, convertedValue);
}
}
else if (IsObjectProperty(property)) // 处理对象属性
{
var subObject = property.GetValue(obj);
ConvertTimeProperties(subObject, timeZoneInfo); // 递归处理子对象
}
}
}
}
/// <summary>
/// 是否为时间属性
/// </summary>
private bool IsDateTimeProperty(PropertyInfo property)
{
return property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?);
}
/// <summary>
/// 是否为对象属性
/// </summary>
private bool IsObjectProperty(PropertyInfo property)
{
return !property.PropertyType.IsValueType && property.PropertyType != typeof(string);
}
}
}
private void ConfigureAbpExceptions(ServiceConfigurationContext context)
{
context.Services.AddMvc
(
options =>
{
options.Filters.Add(typeof(fdbattExceptionFilter));
options.Filters.Add(typeof(fdbattResultFilter));
options.Filters.Add(typeof(UserTimeZoneFilter));
}
).AddJsonOptions(opt =>
{
// 设置异常返回json 属性首字母保持大写
opt.JsonSerializerOptions.PropertyNamingPolicy = null;
});
}
方案二实现过程
后台接口时间属性统一返回UTC
格式,"2024-02-26T18:09:48.2840265Z"
在主服务模块类中设置
Configure<AbpClockOptions>(options => { options.Kind = DateTimeKind.Utc; });
则各接口返回给前端的时间数据为UTC
格式
"CreationTime": "2023-11-20T11:07:32.7027849Z"
前台通过时区转换函数进行时间转换,将其显示为当前用户所在地区的时间
注意:该配置只对框架EFCore
对应表生效,对于自定义表不生效,返回结果格式不准确不带Z;若想生效则需要在具体返回时间数据逻辑里做转换Clock.Normalize(DateTime)
list.ForEach(x => x.StartTime = Clock.Normalize(x.StartTime));
各国时区时间,即User-Timezone
所对应值
/*
Dateline Standard Time,(GMT-12:00)日界线西,国际日期变更线标准时间
Samoa Standard Time,(GMT-11:00) 中途岛,萨摩亚群岛,萨摩亚群岛标准时间
Hawaiian Standard Time,(GMT-10:00) 夏威夷,夏威夷标准时间
Alaskan Standard Time,(GMT-09:00) 阿拉斯加,阿拉斯加标准时间
Pacific Standard Time,(GMT-08:00) 太平洋时间(美国和加拿大);蒂华纳,太平洋标准时间
US Mountain Standard Time,(GMT-07:00) 亚利桑那,美国山地标准时间
Mountain Standard Time,(GMT-07:00) 山地时间(美国和加拿大),山地标准时间
Mexico Standard Time 2,(GMT-07:00)奇瓦瓦,拉巴斯,马扎特兰,墨西哥标准时间 2
Central America Standard Time,(GMT-06:00) 中美洲,中美洲标准时间
Central Standard Time,(GMT-06:00) 中部时间(美国和加拿大),中部标准时间
Canada Central Standard Time,(GMT-06:00) 萨斯喀彻温,加拿大中部标准时间
Mexico Standard Time,(GMT-06:00)瓜达拉哈拉,墨西哥城,蒙特雷,墨西哥标准时间
Eastern Standard Time,(GMT-05:00) 东部时间(美国和加拿大),东部标准时间
US Eastern Standard Time,(GMT-05:00) 印地安那州(东部),美国东部标准时间
SA Pacific Standard Time,(GMT-05:00) 波哥大,利马,基多,南美州太平洋标准时间
SA Western Standard Time,(GMT-04:00) 加拉加斯,拉巴斯,南美州西部标准时间
Pacific SA Standard Time,(GMT-04:00) 圣地亚哥,南美州太平洋标准时间
Atlantic Standard Time,(GMT-04:00) 大西洋时间(加拿大),大西洋标准时间
Newfoundland Standard Time,(GMT-03:30) 纽芬兰,纽芬兰标准时间
E. South America Standard Time,(GMT-03:00) 巴西利亚,南美州东部标准时间
SA Eastern Standard Time,(GMT-03:00) 布宜诺斯艾利斯,乔治敦,南美州东部标准时间
Greenland Standard Time,(GMT-03:00) 格陵兰,格陵兰东部标准时间
Mid-Atlantic Standard Time,(GMT-02:00) 中大西洋,中大西洋标准时间
Azores Standard Time,(GMT-01:00) 亚速尔群岛,亚速尔群岛标准时间
Cape Verde Standard Time,(GMT-01:00) 佛得角群岛,佛得角群岛标准时间
Greenwich Standard Time,(GMT) 卡萨布兰卡,蒙罗维亚,格林威治标准时间
GMT Standard Time,(GMT) 格林威治标准时间: 都柏林, 爱丁堡, 伦敦, 里斯本,格林威治标准时间
W. Central Africa Standard Time,(GMT+01:00) 中非西部,中非西部标准时间
Romance Standard Time,(GMT+01:00) 布鲁塞尔,哥本哈根,马德里,巴黎,罗马标准时间
Central European Standard Time,(GMT+01:00) 萨拉热窝,斯科普里,华沙,萨格勒布,中欧标准时间
Central Europe Standard Time,(GMT+01:00) 贝尔格莱德,布拉迪斯拉发,布达佩斯,卢布尔雅那,布格,中 欧标 准时间
W. Europe Standard Time,(GMT+01:00) 阿姆斯特丹,柏林,伯尔尼,罗马,斯德哥尔摩,维也纳,西欧标时间
South Africa Standard Time,(GMT+02:00) 哈拉雷,比勒陀利亚,南非标准时间
E. Europe Standard Time,(GMT+02:00) 布加勒斯特,东欧标准时间
Egypt Standard Time,(GMT+02:00) 开罗,埃及标准时间
Israel Standard Time,(GMT+02:00) 耶路撒冷,耶路撒冷标准时间
FLE Standard Time,(GMT+02:00) 赫尔辛基,基辅,里加,索非亚,塔林,维尔纽斯,FLE 标准时间
GTB Standard Time,(GMT+02:00) 雅典,贝鲁特,伊斯坦布尔,明斯克,GTB 标准时间
E. Africa Standard Time,(GMT+03:00) 内罗毕,东非标准时间
Arabic Standard Time,(GMT+03:00) 巴格达,阿拉伯标准时间
Arab Standard Time,(GMT+03:00) 科威特,利雅得,阿拉伯标准时间
Russian Standard Time,(GMT+03:00) 莫斯科,圣彼得堡, 伏尔加格勒,俄罗斯标准时间
Iran Standard Time,(GMT+03:30) 德黑兰,伊朗标准时间
Caucasus Standard Time,(GMT+04:00) 巴库,第比利斯,埃里温,高加索标准时间
Arabian Standard Time,(GMT+04:00) 阿布扎比,马斯喀特,阿拉伯半岛标准时间
Afghanistan Standard Time,(GMT+04:30) 喀布尔,阿富汗标准时间
West Asia Standard Time,(GMT+05:00) 伊斯兰堡,卡拉奇,塔什干,西亚标准时间
Ekaterinburg Standard Time,(GMT+05:00) 叶卡捷琳堡,叶卡捷琳堡标准时间
India Standard Time,(GMT+05:30) 马德拉斯,加尔各答,孟买,新德里,印度标准时间
Nepal Standard Time,(GMT+05:45) 加德满都,尼泊尔标准时间
Sri Lanka Standard Time,(GMT+06:00) 斯里哈亚华登尼普拉,斯里兰卡标准时间
N. Central Asia Standard Time,(GMT+06:00) 阿拉木图,新西伯利亚,中亚北部标准时间
Central Asia Standard Time,(GMT+06:00) 阿斯塔纳,达卡,中亚标准时间
Myanmar Standard Time,(GMT+06:30) 仰光,缅甸标准时间
North Asia Standard Time,(GMT+07:00) 克拉斯诺亚尔斯克,北亚标准时间
SE Asia Standard Time,(GMT+07:00) 曼谷,河内,雅加达,东南亚标准时间
North Asia East Standard Time,(GMT+08:00) 伊尔库茨克,乌兰巴图,北亚东部标准时间
China Standard Time,(GMT+08:00) 北京,重庆,香港特别行政区,乌鲁木齐,中国标准时间
Taipei Standard Time,(GMT+08:00) 台北,台北标准时间
Singapore Standard Time,(GMT+08:00) 吉隆坡,新加坡,马来西亚半岛标准时间
W. Australia Standard Time,(GMT+08:00) 珀斯,澳大利亚西部标准时间
Tokyo Standard Time,(GMT+09:00) 大坂,札幌,东京,东京标准时间
Korea Standard Time,(GMT+09:00) 汉城,韩国标准时间
Yakutsk Standard Time,(GMT+09:00) 雅库茨克,雅库茨克标准时间
AUS Central Standard Time,(GMT+09:30) 达尔文,澳大利亚中部标准时间
Cen. Australia Standard Time,(GMT+09:30) 阿德莱德,澳大利亚中部标准时间
West Pacific Standard Time,(GMT+10:00) 关岛,莫尔兹比港,西太平洋标准时间
AUS Eastern Standard Time,(GMT+10:00) 堪培拉,墨尔本,悉尼,澳大利亚东部标准时间
E. Australia Standard Time,(GMT+10:00) 布里斯班,澳大利亚东部标准时间
Vladivostok Standard Time,(GMT+10:00) 符拉迪沃斯托克,符拉迪沃斯托克标准时间
Tasmania Standard Time,(GMT+10:00) 霍巴特,塔斯马尼亚岛标准时间
Central Pacific Standard Time,(GMT+11:00) 马加丹,索罗门群岛,新喀里多尼亚,太平洋中部标准时间
New Zealand Standard Time,(GMT+12:00) 奥克兰,惠灵顿,新西兰标准时间
Fiji Standard Time,(GMT+12:00) 斐济,堪察加半岛,马绍尔群岛,斐济标准时间
Tonga Standard Time,(GMT+13:00) 努库阿洛法,汤加标准时间
*/