C# 时间属性数据所涉及的时区转换解决方案

C# 时间属性数据所涉及的时区转换解决方案

说明:开发一个可能跨国跨时区的云平台。其中,不同地区的用户访问平台时,所浏览的相关时间数据为当前地区所在的时区时间。

前提:平台所涉及到的时间属性所存储的数据需统一定义为UTCGMT时间。

方案一:

  • 前台处理:前台获取当前用户使用设备所在地区时区信息,并将相关时区信息设置在平台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) 努库阿洛法,汤加标准时间
*/

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值