在get和set中转换c# datetime属性到utc和从utc转换是不是很糟糕?
本文关键字:转换 utc 是不是 和从 属性 get set datetime | 更新日期: 2023-09-27 18:17:56
在我们的实体框架应用程序中,我们将日期时间存储为UTC。客户端使用反射实用程序将对象图转换为其用户时区,然后在向服务器提交更改时返回到utc。
实用程序工作得很好,但我正在考虑一种更干净的方法,我在基类上添加一个未映射的TimeZoneInfo属性,默认值设置为UTC,然后对于每个datetime属性,我将像这样修改它:
private DateTime _endTime;
public DateTime EndTime
{
get
{
return _endTime.ConvertFromUtc(TimeZone);
}
set
{
_endTime = value.ConvertToUtc(TimeZone);
}
}
的想法是,支持字段始终存储为一个UTC值。如果TimeZone属性被设置为UTC,那么ConvertTo/From扩展方法将不会进行任何转换,而只是返回支持字段的值。然而,如果TimeZone被设置为其他任何值,那么转换将发生,保留UTC格式的backing字段。
我想知道的是是否有我没有想到的问题。例如,我假设它将使用基于当前TimeZone属性的值进行序列化…这是真的吗?此外,这是否适用于EF中的代码优先实体?我的希望是,如果TimeZone被更改,它将而不是触发dbcontext中的更改。我是否还遗漏了其他会使这成为一个坏主意的考虑因素? DDD实现者会怎么想?
编辑为了更清楚地说明用例,服务层将从数据库中检索值,进行序列化,并将其发送给MVC控制器。服务层不知道用户的时区。在我的mvc应用程序中,web控制器在登录时缓存用户的时区。然后,该控制器将使用该值设置对象上的TimeZone属性。然后它将通过JSON提交给客户端。基类上的TimeZone属性表示对象的当前时区,而不是用户的时区。这些值始终存储为UTC,并且将数据发送给客户端的控制器负责确保将其设置为正确的时区。
我考虑这个的最大原因是业务逻辑。所讨论的对象是一个具有开始和结束时间的时间表。如果将对象设置为用户时区,有三个需求将更容易执行。例如,日程安排不能跨越几周,所以如果它开始于周六(一周的结束),结束于周日(一周的开始),它必须分成两个不同的日程安排。由于某种原因,我在处理日期时间逻辑时更困难,所以我可以做的任何事情来简化它是维护的一个加分项。
问题是你的应用程序的时区将是web服务器的时区!如果用户从另一个时区访问您的网站,那么转换将是错误的。
你需要让你的页面通过浏览器确定他们的时区,并使用它进行转换。
如果你需要用户的当前时间,你可以这样做:
Date.now()
// Or this if you need support for old browsers, like IE8
new Date().getTime()
将给出自1970年1月1日以来以毫秒为单位的UTC时间。之后,你必须在你的应用程序中将其转换为c#时间:
DateTime date = new DateTime(valueFromJS * 10000 + 621355860000000000);
如果你不需要当前时间,而是用户在日期选择器中输入的日期+时间,那么你应该在浏览器中创建一个日期对象,并发送该对象的getTime()
。这样你的web服务器总是接收到UTC时间,这取决于浏览器做适当的转换。
您还可以使用new Date().getTimezoneOffset()
,它将返回UTC比用户时区早的分钟数。因此,如果用户在GMT -4中,该函数将返回240。如果出于某种原因,您需要在web服务器中使用该值,则可以从浏览器发送该值。或者,如果您的应用程序有用户,您甚至可以将其存储为设置并简单地使用它。
现在,要在浏览器的时区中显示日期,你必须事先知道用户的时区(从以前的请求或用户设置),或者只是用UTC发送它,然后在浏览器中通过JavaScript转换它。
还有一些有用的库可以处理时区问题。例如:
http://momentjs.com/timezone/http://tzdata-javascript.org我觉得我的问题措辞不太好,也没有经过深思熟虑。我决定在我的项目中执行上述想法,并发现它只会产生更多的困惑。它也增加了太多的风险,特别是如果在持久化到db的对象中使用,程序员可能无法将对象转换回utc。
相反,我添加了一个更简单的方法,通过添加一个扩展方法来轻松地根据指定的时区进行计算。扩展方法假定datetime对象是UTC格式的:
public static DateTime? As(this DateTime? dt, TimeZoneInfo targetTimeZone)
{
if (dt.HasValue)
return dt.Value.As(targetTimeZone);
else
return dt;
}
public static DateTime As(this DateTime dt, TimeZoneInfo targetTimeZone)
{
return TimeZoneInfo.ConvertTimeFromUtc(dt, targetTimeZone);
}