DateTime 比较忽略类型?
DateTime Compare Ignores Kind?
DateTime d1=new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime d2=new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Local);
Console.WriteLine(d1==d2); // prints true
Console.WriteLine(d1<d2); // prints false
Console.WriteLine(d1.CompareTo(d2)); // prints 0
Console.WriteLine(d1.ToUniversalTime()==d2.ToUniversalTime()); // prints false
这对我来说似乎是一个错误,如果不是的话color me surprised。
每次比较我都必须调用 ToUniversalTime() 还是有更好的选择?
如何避免因 DateTimeKind.Unspecified 而忘记调用 ToUniversalTime() 或得到错误结果等陷阱?
MSDN 文档非常清楚,DateTimeKind
未考虑使用相等运算符。
The Equality operator determines whether two DateTime values are equal by comparing their number of ticks. Before comparing DateTime objects, make sure that the objects represent times in the same time zone. You can do this by comparing the values of their Kind property.
MSDN - DateTime.Equality Operator
您可以编写自己的扩展方法以包含 DateTimeKind
比较:
public static bool EqualsWithKind(this DateTime time, DateTime other)
{
return time.Kind == other.Kind &&
time == other;
}
考虑到 Panagiotis Kanavos 和 James Thorpe 关于 DateTimeOffset
的评论:
如果保证偏移量与本地偏移量相同则使用。
public static bool EqualsWithTimezone(this DateTime time, DateTime other)
{
return new DateTimeOffset(time) == new DateTimeOffset(other);
}
如果偏移量不能保证相同则使用:
public static bool EqualsInclTimezone(this DateTime time, TimeSpan timeOffset, DateTime other, TimeSpan otherOffset)
{
return new DateTimeOffset(time, timeOffset) == new DateTimeOffset(other, otherOffset);
}
在我看来是正确的。
2015 年 1 月 1 日 15:00:00 (utc)(也是 GMT - 等于 GMT 格林威治标准时间)
2015 年 1 月 1 日 15:00:00(当地时间 - 假设当地时间在纽约市)
这两个时间和日期相比之下是相等的。
但是将第二个转换为 UTC,它会提前 5 小时变成
UTC/GMT
1/1/2015 20:00:00 - 它们不再相等!
这不完全是错误,而是 DateTime
的缺点。除了 local/UTC 指示符外,DateTime
类型不支持时区信息。它在文档中是这样说的——你必须确保日期在同一时区——而不仅仅是具有相同的种类。 DateTimeKind.Local
没有说明真正使用的时区。
如果您关心时区,则应始终使用 DateTimeOffset 类型。它在 .NET 3.5 中引入,部分是为了解决时区问题。 DateTimeOffset 相当于SQL 服务器的datetimeoffset
类型,包含时区偏移和时间,允许时区 偏移 之间的比较和转换。这也允许您在代码和数据库中存储和使用完整的时间信息,避免转换错误。
这类似于使用 nvarchar
而不是 varchar
来避免代码页转换错误。
由于夏令时,时区可能有不同的偏移量。夏令时规则也会不时更改 - 俄罗斯规则在过去 10 年中至少更改了 4 次。 Windows 和 .NET 对此没有修复。
这可能是旅游业中的一个问题。在这种情况下,您可以使用像 Noda Time 这样的库,它包含具有所有已知时区规则的 IANA 时区数据库。
DateTime d1=new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime d2=new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Local);
Console.WriteLine(d1==d2); // prints true
Console.WriteLine(d1<d2); // prints false
Console.WriteLine(d1.CompareTo(d2)); // prints 0
Console.WriteLine(d1.ToUniversalTime()==d2.ToUniversalTime()); // prints false
这对我来说似乎是一个错误,如果不是的话color me surprised。
每次比较我都必须调用 ToUniversalTime() 还是有更好的选择?
如何避免因 DateTimeKind.Unspecified 而忘记调用 ToUniversalTime() 或得到错误结果等陷阱?
MSDN 文档非常清楚,DateTimeKind
未考虑使用相等运算符。
The Equality operator determines whether two DateTime values are equal by comparing their number of ticks. Before comparing DateTime objects, make sure that the objects represent times in the same time zone. You can do this by comparing the values of their Kind property.
MSDN - DateTime.Equality Operator
您可以编写自己的扩展方法以包含 DateTimeKind
比较:
public static bool EqualsWithKind(this DateTime time, DateTime other)
{
return time.Kind == other.Kind &&
time == other;
}
考虑到 Panagiotis Kanavos 和 James Thorpe 关于 DateTimeOffset
的评论:
如果保证偏移量与本地偏移量相同则使用。
public static bool EqualsWithTimezone(this DateTime time, DateTime other)
{
return new DateTimeOffset(time) == new DateTimeOffset(other);
}
如果偏移量不能保证相同则使用:
public static bool EqualsInclTimezone(this DateTime time, TimeSpan timeOffset, DateTime other, TimeSpan otherOffset)
{
return new DateTimeOffset(time, timeOffset) == new DateTimeOffset(other, otherOffset);
}
在我看来是正确的。
2015 年 1 月 1 日 15:00:00 (utc)(也是 GMT - 等于 GMT 格林威治标准时间)
2015 年 1 月 1 日 15:00:00(当地时间 - 假设当地时间在纽约市)
这两个时间和日期相比之下是相等的。
但是将第二个转换为 UTC,它会提前 5 小时变成 UTC/GMT
1/1/2015 20:00:00 - 它们不再相等!
这不完全是错误,而是 DateTime
的缺点。除了 local/UTC 指示符外,DateTime
类型不支持时区信息。它在文档中是这样说的——你必须确保日期在同一时区——而不仅仅是具有相同的种类。 DateTimeKind.Local
没有说明真正使用的时区。
如果您关心时区,则应始终使用 DateTimeOffset 类型。它在 .NET 3.5 中引入,部分是为了解决时区问题。 DateTimeOffset 相当于SQL 服务器的datetimeoffset
类型,包含时区偏移和时间,允许时区 偏移 之间的比较和转换。这也允许您在代码和数据库中存储和使用完整的时间信息,避免转换错误。
这类似于使用 nvarchar
而不是 varchar
来避免代码页转换错误。
由于夏令时,时区可能有不同的偏移量。夏令时规则也会不时更改 - 俄罗斯规则在过去 10 年中至少更改了 4 次。 Windows 和 .NET 对此没有修复。
这可能是旅游业中的一个问题。在这种情况下,您可以使用像 Noda Time 这样的库,它包含具有所有已知时区规则的 IANA 时区数据库。