为什么要存储UTC时间
存储UTC(协调世界时)时间是为了在跨时区和时间转换的情况下保持时间的一致性和准确性。以下是一些原因:
-
时区独立性:UTC时间是不受时区影响的,它是全球标准时间。通过存储UTC时间,可以避免在不同时区之间进行转换和处理,确保时间的一致性,无论用户位于何处。
-
跨时区应用:对于涉及跨时区操作的应用程序,使用UTC时间可以简化时间计算和比较。如果存储本地时间,可能会面临时区转换和夏令时变更等问题,导致时间计算不准确。
-
数据一致性:当多个系统或数据库需要共享时间信息时,使用UTC时间可以确保数据的一致性。不同系统和数据库可以根据需要将UTC时间转换为本地时间进行显示,以满足用户的需求,而不会引起数据不一致的问题。
-
日志和审计:在日志记录和审计方面,使用UTC时间可以提供统一的时间戳,使得跨系统和跨地点的日志可以进行准确的时间排序和比较。
-
时间计算的准确性:在进行时间计算、持续时间计算或时间间隔比较时,使用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时间再转回当前时区的实现
在 Controller
和 Services
及Repository
就不用再处理Datetime 类型时区转换的代码了, 直接可以使用