在特定时区找到 LocalDate 的最后可能时刻的最巧妙方法是什么?
What is the neatest way to find the last possible instant of a LocalDate, in a particular time-zone?
抱歉,如果这看起来是一个简单的问题,但我主要只是想检查一下我拥有的解决方案是否对所有情况都是最sensible/holds。
我们使用的预先存在的 SQL 服务器数据库存储一个 'period' 作为包含开始 -> 包含结束 UTC 日期时间值。 (开始和结束列都是 datetime2(7)
,在我们开始使用它们之前自动转换为 DateTimeKind.UTC
的 System.DateTime
实例。
所以,如果我需要存储 "whole day/month/year, given the user's time-zone",我需要找到 "The last possible instant of a specified LocalDate, in a particular DateTimeZone".
我有的方法如下:
public static LocalDateTime AtEndOfDay(this LocalDate localDate)
{
return localDate
.PlusDays(1)
.AtMidnight()
.PlusTicks(-1);
}
public static ZonedDateTime AtEndOfDay(this DateTimeZone zone, LocalDate localDate)
{
return zone
.AtStartOfDay(localDate.PlusDays(1))
.Plus(Duration.FromTicks(-1));
}
我认为我还需要避免(在其他任何地方)使用 .AtLeniently(..)
映射 "end of date" LocalDateTime
因为如果 23:59:59.9999999 是 "skipped" 并且在目标 DateTimeZone
中不存在,那么它将被映射到间隙 00:00:00.000000 的 'outer' 侧的下一个可用时刻,这将给我一个 独家ZonedDateTime
超值
修正方法:
public static LocalDateTime AtEndOfDay(this LocalDate localDate)
{
// TODO: Replace with localDate.At(LocalTime.MaxValue) when NodaTime 2.0 is released.
return localDate
.PlusDays(1)
.AtMidnight()
.PlusTicks(-1);
}
public static ZonedDateTime AtEndOfDay(this DateTimeZone zone, LocalDate localDate)
{
return zone
.AtStartOfDay(localDate.PlusDays(1))
.Plus(-Duration.Epsilon);
}
public static ZonedDateTime AtEndOfDayInZone(this LocalDate localDate, DateTimeZone zone)
{
return zone.AtEndOfDay(localDate);
}
首先,如评论中所述,任何时候您 可以 使用独占上限,这将是一个好主意 :)
你的 AtEndOfDay
方法对我来说看起来很合理,除了我会使用 Duration.Epsilon
而不是 Duration.FromTicks
。特别是,在 Noda Time 2.0 中,我们将移动到纳秒而不是滴答的精度; Duration.Epsilon
在这两种情况下都会做你想做的事。
对于您的 LocalDate
解决方案,在我看来我们缺少 LocalTime.MaxValue
(或 EndOfDay
)的值,这是最大的可表示值 LocalTime
。如果可用,您可以只写:
return date.At(LocalTime.MaxValue);
这将消除与以前相同的 "ticks" 问题。我会尽量记住为 2.0 添加它 - 尽管它将被记录为 "Only use this if you're forced to by legacy systems" :)
添加一天然后减去一个刻度(或纳秒)的一个缺点是它会在 LocalDate.MaxValue
上失败。这可能不是一个 实际 问题,但对于 Noda Time 本身的代码,我们尽量避免这样的事情。不过,对于 ZonedDateTime
版本,我不会尝试避免它,因为这是一个相当复杂的场景。 (可能有一些方法可以做到,但不值得。)
抱歉,如果这看起来是一个简单的问题,但我主要只是想检查一下我拥有的解决方案是否对所有情况都是最sensible/holds。
我们使用的预先存在的 SQL 服务器数据库存储一个 'period' 作为包含开始 -> 包含结束 UTC 日期时间值。 (开始和结束列都是 datetime2(7)
,在我们开始使用它们之前自动转换为 DateTimeKind.UTC
的 System.DateTime
实例。
所以,如果我需要存储 "whole day/month/year, given the user's time-zone",我需要找到 "The last possible instant of a specified LocalDate, in a particular DateTimeZone".
我有的方法如下:
public static LocalDateTime AtEndOfDay(this LocalDate localDate)
{
return localDate
.PlusDays(1)
.AtMidnight()
.PlusTicks(-1);
}
public static ZonedDateTime AtEndOfDay(this DateTimeZone zone, LocalDate localDate)
{
return zone
.AtStartOfDay(localDate.PlusDays(1))
.Plus(Duration.FromTicks(-1));
}
我认为我还需要避免(在其他任何地方)使用 .AtLeniently(..)
映射 "end of date" LocalDateTime
因为如果 23:59:59.9999999 是 "skipped" 并且在目标 DateTimeZone
中不存在,那么它将被映射到间隙 00:00:00.000000 的 'outer' 侧的下一个可用时刻,这将给我一个 独家ZonedDateTime
超值
修正方法:
public static LocalDateTime AtEndOfDay(this LocalDate localDate)
{
// TODO: Replace with localDate.At(LocalTime.MaxValue) when NodaTime 2.0 is released.
return localDate
.PlusDays(1)
.AtMidnight()
.PlusTicks(-1);
}
public static ZonedDateTime AtEndOfDay(this DateTimeZone zone, LocalDate localDate)
{
return zone
.AtStartOfDay(localDate.PlusDays(1))
.Plus(-Duration.Epsilon);
}
public static ZonedDateTime AtEndOfDayInZone(this LocalDate localDate, DateTimeZone zone)
{
return zone.AtEndOfDay(localDate);
}
首先,如评论中所述,任何时候您 可以 使用独占上限,这将是一个好主意 :)
你的 AtEndOfDay
方法对我来说看起来很合理,除了我会使用 Duration.Epsilon
而不是 Duration.FromTicks
。特别是,在 Noda Time 2.0 中,我们将移动到纳秒而不是滴答的精度; Duration.Epsilon
在这两种情况下都会做你想做的事。
对于您的 LocalDate
解决方案,在我看来我们缺少 LocalTime.MaxValue
(或 EndOfDay
)的值,这是最大的可表示值 LocalTime
。如果可用,您可以只写:
return date.At(LocalTime.MaxValue);
这将消除与以前相同的 "ticks" 问题。我会尽量记住为 2.0 添加它 - 尽管它将被记录为 "Only use this if you're forced to by legacy systems" :)
添加一天然后减去一个刻度(或纳秒)的一个缺点是它会在 LocalDate.MaxValue
上失败。这可能不是一个 实际 问题,但对于 Noda Time 本身的代码,我们尽量避免这样的事情。不过,对于 ZonedDateTime
版本,我不会尝试避免它,因为这是一个相当复杂的场景。 (可能有一些方法可以做到,但不值得。)