有人问过,但我正在努力掌握如何在网络应用程序中处理时区的概念。我有一个跟踪项目进度的系统。我的 SQL Server 数据库中有一个 ProjectStartDate DATE。(还有一些字段和表,但让我们专注于一个)。
服务器位于美国某处。我住在澳大利亚。
调用SELECT GETDATE()
返回“2013-08-11 14:40:50.630”我的系统时钟显示“2013-08-12 07:40”
在我的数据库中,所有表上都有“CreateDateTime”列。当我在我的 c# 代码中存储它时,我使用CreateDate = DateTime.UtcNow
我使用它,因为我听说使用 UTC 更好。
但是,当用户看到日历控件并且他们为项目选择开始日期时,我会存储用户选择的任何内容。没有转换......正如我所说, StartDate 是数据库中的 DATE 类型。
问题是,如果一个项目今天开始 - 我的前端说当前项目没有开始,因为服务器仍然在昨天。
我认为日期应该在我存储它们时存储。但也许我需要以某种方式获取用户时区,并将其应用到 UI 级别?
我看到的问题是:
- 我不知道用户的时区。添加一些东西让他们选择吗?
- 项目的状态可能在存储过程中确定,那么我什么时候可以应用转换?在 proc 中,它可能会进行检查,如果 StartDate <= DateTime.Now?
我大部分时间使用 EntityFramework 和 Linq 来获取数据。我需要一种从 SQL 意义上和 .Net 意义上插入和检索数据的策略。
我添加了代码让用户根据这个选择他们的时区:
public List<TimeZoneDto> GetTimeZones()
{
var zones = TimeZoneInfo.GetSystemTimeZones();
var result = zones.Select(tz => new TimeZoneDto
{
Id = tz.Id,
Description = tz.DisplayName
}).ToList();
return result;
}
然后将其保留在他们的个人资料中。
正如以下答案中所建议的,所有日期都存储为 UTC。
我仍然很困惑如何处理他们往返数据库和客户端的日期。这是我如何存储记录的示例:
public int SaveNonAvailibility(PersonNonAvailibilityDto n)
{
person_non_availibility o;
if (n.Id == 0)
{
o = new person_non_availibility
{
PersonId = n.PersonId,
Reason = n.Reason,
StartDate = n.StartDate,
EndDate = n.EndDate,
NonAvailibilityTypeId = n.NonAvailibilityTypeId,
CreateUser = _userId,
CreateDate = DateTime.UtcNow
};
_context.person_non_availibility.Add(o);
}
else
{
o = (from c in _context.person_non_availibility where c.Id == n.Id select c).FirstOrDefault();
o.StartDate = n.StartDate;
o.EndDate = n.EndDate;
o.Reason = n.Reason;
o.NonAvailibilityTypeId = n.NonAvailibilityTypeId;
o.LastUpdateDate = DateTime.UtcNow;
o.LastUpdateUser = _userId;
o.Deleted = n.Deleted ? DateTime.UtcNow : (DateTime?)null;
}
_context.SaveChanges();
return o.Id;
}
这种方法基本上可以节省一个人无法工作的时间。请注意我存储 LastUpdateDate 的方式。此外,“开始”和“结束”日期。这些日期是更多的“商务”日期。
在选择,然后是日期检查时,我遇到了问题。在此示例中,我正在获取基于 NOW 的个人收费率。
public decimal CurrentRate
{
get
{
if (ResourceCosts != null)
{
var i = ResourceCosts.FirstOrDefault(t => DateTime.UtcNow <= (t.EndDate.HasValue ? t.EndDate.Value : DateTime.UtcNow) && DateTime.UtcNow >= t.StartDate);
if (i != null) return i.Cost;
return 0;
}
return 0;
}
}
所以,我想在这里做的是,根据当前日期,我想看看他的费率(因为他的收费我们的费率可能是从 1 月 1 日到 1 月 15 日的 100 美元,然后从 16 日到 110 美元) 1 月 31 日。所以,我寻找今天适用的汇率(如果有的话)。这不适用于跨时区,可能在这里我需要根据“DateTime.UTCNow”进行一些日期操作?
请注意,我现在根据上面存储用户时区的代码知道用户时区。我可以在这里以某种方式使用它吗?也许,当用户登录时,从他的个人资料(Zimezone 信息)中获取日期信息,然后拥有一个全局共享函数,该函数根据从 UTC 日期添加或删除小时数返回用户日期时间......并使用它我在哪里做 DateTime.UTCNow?
希望有人可以指导我。