惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

腾讯CDC
The Cloudflare Blog
IT之家
IT之家
V
V2EX
雷峰网
雷峰网
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
Stack Overflow Blog
Stack Overflow Blog
博客园 - Franky
Engineering at Meta
Engineering at Meta
S
SegmentFault 最新的问题
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
小众软件
小众软件
博客园 - 叶小钗
Blog — PlanetScale
Blog — PlanetScale
C
Check Point Blog
A
About on SuperTechFans
B
Blog
月光博客
月光博客
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI

忘忧的小站

SqlServer高频面试题(持续更新251114) | 忘忧的小站 MySql入门:备份恢复与安全管理 | 忘忧的小站 MySql入门:高可用与架构设计 | 忘忧的小站 MySql入门:SQL编程与高级特性 | 忘忧的小站 MySql入门:性能优化与调优 | 忘忧的小站 MySql入门:MySQL数据类型与表设计 | 忘忧的小站 MySql入门:MySQL核心概念与架构解析 | 忘忧的小站 Redis配置文件及常用命令详解 | 忘忧的小站 Redis入门:总结与展望 | 忘忧的小站 Redis入门:进阶知识与运维管理 | 忘忧的小站 Redis入门:Redis在项目中的实战应用 | 忘忧的小站 Redis入门:Redis的持久化与高可用 | 忘忧的小站 Redis入门:玩转Redis五大核心数据结构 | 忘忧的小站 Redis入门:Redis核心概念与快速入门 | 忘忧的小站 Lucene.Net 分布式索引实现方案 | 忘忧的小站 Lucene.Net 入门和简单使用 | 忘忧的小站 JavaScript授权Gps,音频,视频踩坑 | 忘忧的小站 Abp.Zero框架升级 | 忘忧的小站 mysql每日自动备份数据 | 忘忧的小站
.Net7 针对Utc时区转换问题中间件 | 忘忧的小站
本文作者: 忘忧 · 2023-11-01 · via 忘忧的小站

发表于 | 分类于 .Net Core | 0 | 阅读次数 2817

为什么要存储UTC时间

存储UTC(协调世界时)时间是为了在跨时区和时间转换的情况下保持时间的一致性和准确性。以下是一些原因:

  1. 时区独立性:UTC时间是不受时区影响的,它是全球标准时间。通过存储UTC时间,可以避免在不同时区之间进行转换和处理,确保时间的一致性,无论用户位于何处。

  2. 跨时区应用:对于涉及跨时区操作的应用程序,使用UTC时间可以简化时间计算和比较。如果存储本地时间,可能会面临时区转换和夏令时变更等问题,导致时间计算不准确。

  3. 数据一致性:当多个系统或数据库需要共享时间信息时,使用UTC时间可以确保数据的一致性。不同系统和数据库可以根据需要将UTC时间转换为本地时间进行显示,以满足用户的需求,而不会引起数据不一致的问题。

  4. 日志和审计:在日志记录和审计方面,使用UTC时间可以提供统一的时间戳,使得跨系统和跨地点的日志可以进行准确的时间排序和比较。

  5. 时间计算的准确性:在进行时间计算、持续时间计算或时间间隔比较时,使用UTC时间可以避免由于夏令时等因素引起的时间偏移和不一致性,确保计算的准确性。

总之,存储UTC时间可以提供时间的一致性、跨时区操作的便利性以及数据的一致性,尤其适用于涉及多个时区的应用程序和系统。当需要进行时间转换或比较时,可以将UTC时间转换为本地时间进行显示,以满足最终用户的需求。

代码中实现

var dateTime = Datetime.UtcNow;

如果这样实现的话那么接口请求的时间和请求返回的时间都需要手动处理,这样不不够优雅的

如何处理

安装Newtonsoft.Json
增加DateTimeFilter.cs

public class DateTimeFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        var parameters = context.ActionArguments;
        foreach (var parameter in parameters)
        {
           
            if (parameter.Value is DateTime dateTime)
            {
                dateTime = dateTime.ToUniversalTime();
                context.ActionArguments[parameter.Key] = dateTime;
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
    }
}

增加DateTimeJsonConverter.cs

public class DateTimeJsonConverter : DateTimeConverterBase
{
    
    public DateTimeJsonConverter()
    {
    }
  
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

        
        
        // 用户配置的时区 ,建议使用Redis 或者内存缓存
        var setting = "";
        if (setting.IsNullOrEmpty())
        {
            DateTime dateTime = (DateTime)value;
            writer.WriteValue(dateTime.ToLocalTime());
        }
        else
        {
            TimeZoneInfo targetTimeZone = TimeZoneInfo.FindSystemTimeZoneById(setting);
            DateTime targetTime = TimeZoneInfo.ConvertTimeFromUtc((DateTime) value, targetTimeZone);
            writer.WriteValue(targetTime);
        }

    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        DateTime dateTime = (DateTime)reader.Value;
        return dateTime.ToUniversalTime();
    }
}

在Program.cs 中注册

builder.Services.AddControllers(o =>
{
        o.Filters.Add(typeof(DateTimeFilter));
}).AddNewtonsoftJson(options =>
{
    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
    options.SerializerSettings.Converters.Add(new StringEnumConverter());
    options.SerializerSettings.Converters.Add(new DateTimeJsonConverter());

})

DateTimeFilter 是针对以下接口入参形式

        [HttpGet("utc")]
        public IActionResult Utc(DateTime utc)
        {
            return Ok(utc);
        }

DateTimeJsonConverter 是捕获不到接口的参数,只能捕获入参对象,和返回对象

    public class MyClass
        {
            public DateTime Utc { get; set; }
            
            public MyClass1 MyClassx { get; set; }
            public class MyClass1
            {
                public DateTime Utc1 { get; set; }
            }
        }
        [HttpGet("utc")]
        public IActionResult Utc(MyClass utc)
        {
            return Ok(utc);
        }
        
        //获取所有时区
         [HttpGet("TimeZone")]
        public IActionResult List()
        {
            var list = TimeZoneInfo.GetSystemTimeZones();
            return Ok(list.Select(x =>
            {
                return new
                {
                    Id = x.Id,
                    DisplayName = x.DisplayName
                };
            }).ToList());
        }

这样就实现对传入参数和返回参数 DateTime 类型转UTC时间再转回当前时区的实现
ControllerServicesRepository就不用再处理Datetime 类型时区转换的代码了, 直接可以使用

  • 本文链接: /archives/183
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!