无论日期如何,都要比较时间

时间:2013-08-29 13:17:42

标签: c# .net datetime

我有一个对象,其属性当前为DateTime。

该对象在一个时间范围内被标记为有效。默认值为00:00:00至23:59:59

用户在UI中输入值,并通过以下方式设置属性:

new DateTime(DateTime.Now.Year, 
             DateTime.Now.Month, 
             DateTime.Now.Day, 
             model.Hours, 
             model.Minutes, 
             model.Seconds)

然后在遇到数据库时将其转换为UTC。

今天的日期是2013年8月29日。如果印度的同事运行此计划,它将在2013年8月28日18:30:00将数据存储在数据库中,因为它们比UTC早5.5小时,因此2013年8月29日00:00 :00成为昨天。

当逻辑尝试确定对象是否有效时,逻辑是:

if (DateTime.UtcNow.TimeOfDay > model.MyPropertyFromDB.TimeOfDay)

我们正在尝试确定当前时间是否在00:00:00和23:59:59范围内

这是因为14:00(当前时间)不大于18:30

比较时间的最佳方法是什么?

将值存储为DateTimeOffSet帮助,是否使用ToLocal()确定?

其他考虑因素是印度的用户正在使用托管在英国的应用,因此需要了解时区。

由于

3 个答案:

答案 0 :(得分:2)

和其他人一样,我仍然不清楚你到底想要什么。但显然,你不应该这样做:

new DateTime(DateTime.Now.Year, 
             DateTime.Now.Month, 
             DateTime.Now.Day, 
             model.Hours, 
             model.Minutes, 
             model.Seconds)

那会更好:

DateTime.Today.Add(new TimeSpan(model.Hours, model.Minutes, model.Seconds))

但是你为什么要这样做呢?这些中的任何一个都会返回 local 日期。我假设这将在服务器上运行,所以你真的希望服务器的时区影响这个结果吗?可能不是。请阅读:The Case Against DateTime.Now

如果您想要UTC日期,可以这样做:

DateTime.UtcNow.Date.Add(new TimeSpan(model.Hours, model.Minutes, model.Seconds))

无论服务器的时区如何,这至少会普遍相同。但是,我认为这不是你想要的。

为什么是用户在分配当前日期时仅输入时间的原因尚不清楚。如果日期是相关的,那么用户不应该输入它并且它将成为模型的一部分吗?

如果日期不相关,那么为什么要存储它?您可以在内部使用TimeSpan类型作为时间值。您没有说出您的数据库是什么,但我们只是猜测它是SQL Server,在这种情况下您可以在表中的字段上使用time类型。

我认为日期可能是相关的,但你想控制它,而用户则控制提供时间。如果是这种情况,那么必须知道用户的时区(或者如果不是用户,则为上下文的时区)。假设您有一个Windows时区标识符(请参阅the timezone tag wiki),那么您可以执行以下操作:

var tz = TimeZoneInfo.FindSystemTimeZoneById(theTimeZoneId);
var local = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz);
var dt = local.Date.Add(new TimeSpan(model.Hours, model.Minutes, model.Seconds));

如果您没有时区信息,则无法解决此问题。

作为一般建议,您可能想尝试使用Noda Time而不是内置的东西。它可以帮助你弄清楚这种事情。从主页:

  

Noda Time是.NET的替代日期和时间API。它可以帮助您更清晰地考虑数据,并更准确地表达对数据的操作。

这似乎直接是你在这里遇到的问题。如果你想澄清我提出的一些问题,我很乐意编辑我的答案,并告诉你如何用Noda Time做到这一点。

为什么你的问题令人困惑

  

我们正在尝试确定当前时间是否在00:00:00和23:59:59范围内

所有次都在该范围内。好吧,也许像23:59:59.1这样的值可能会超出它,但你不会在模型中收集小数秒,所以这是无关紧要的。但为什么你需要验证呢?也许你只是想避免完全没有时间的数字?喜欢99:99:99

  

这是因为14:00(当前时间)不大于18:30

等等 - 你没有说过比一次大于另一次的比较。 14:0018:30都在您指定的范围内。

  

比较时间的最佳方法是什么?

很难回答。它们都是UTC时代吗?是UTC还是一个本地?他们都是本地人吗?你知道当地时间吗?您是否准备好处理模糊或无效的当地时间以进行夏令时转换?

  

将值存储为DateTimeOffSet帮助吗?

也许,但你没有给我足够的信息。仅当日期部分相关并且您获得正确的偏移量时,它才有用。

  

正在使用ToLocal()确定?

我认为不,不行。本上下文中的本地将为您提供服务器的时区,您可能不希望将其引入业务逻辑。

答案 1 :(得分:0)

因此,如果我理解正确,您在数据库中有一个以UTC保存的时间,并且您正在尝试确定它是否属于特定时间范围内?我不确定你是否想要本地时间或UTC的时间框架,所以这两者都是:

DateTime dbTime = model.MyPropertyFromDB;

TimeSpan minTime = new TimeSpan(0, 0, 0);
TimeSpan maxTime = new TimeSpan(23, 59, 59);

if (dbTime.TimeOfDay > minTime && dbTime.TimeOfDay < maxTime)
{
    //Within time range (UTC)
}

if (dbTime.ToLocalTime().TimeOfDay > minTime && dbTime.ToLocalTime().TimeOfDay < maxTime)
{
    //Within time range (local)
}

编辑:如果要将现在与数据库中对象的开始和结束时间进行比较:

TimeSpan now = DateTime.UtcNow.TimeOfDay;
TimeSpan startDate = model.startDate.TimeOfDay;
TimeSpan endDate = model.endDate.TimeOfDay;

if (now > startDate && now < endDate)
{
    //Within time range (UTC)
}

答案 2 :(得分:0)

我想说这里使用的方法存在根本缺陷,你需要采取不同的方法。

new DateTime(DateTime.Now.Year,   // Server date
             DateTime.Now.Month, 
             DateTime.Now.Day, 
             model.Hours,         // Local time
             model.Minutes, 
             model.Seconds)

我无法通过这种方式看到一种“正常化”输入的方法,除非你有办法可靠地确切地知道用户所处的时区。简单地说,没有简单的方法来改变以这种方式构建的日期到UTC。

我的第一个问题是,模型是如何从客户端传递到服务器的?如果您正在使用javascript / ajax,那么解决方案应该通过在客户端上构建datetime对象(包括它们的时区数据)来解决,然后依靠浏览器将其转换为UTC进行传输。

如果您正在使用Razor \ MVC,那么您可以使用表单编码实现类似的功能,但您需要在服务器上调用ToUTC,因为浏览器不会自动为您定义此媒体格式的日期。< / p>

这两种方法都要求您在客户端上构建完整的datetime对象,然后提交它,而不是尝试在服务器上的秒,分钟,小时内构建它。当然,只要日期时间在提交时完全形成,您就不需要将所有这些暴露给客户端。

一旦你有一个漂亮的UTC日期时间,如果你不需要剩下的时间,你可以只提取时间。

希望这有帮助。

皮特