在特定时区找到 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.UTCSystem.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 版本,我不会尝试避免它,因为这是一个相当复杂的场景。 (可能有一些方法可以做到,但不值得。)