在特定时区找到LocalDate的最后可能瞬间的最佳方法是什么?

时间:2015-02-02 10:18:04

标签: c# nodatime

道歉,如果这似乎是一个简单的问题,但我大多只是想检查我所拥有的解决方案对于所有情况都是最明智/最有效的。

我们使用的预先存在的SQL Server数据库存储了一个'期间'作为包容性的开始 - >包含结束UTC DateTime值。 (开始和结束列都是datetime2(7),在我们开始使用它们之前会自动转换为System.DateTime DateTimeKind.UTC个实例。

所以,如果我需要存储"整天/月/年,给定用户的时区"我需要在特定的DateTimeZone" 中找到"指定LocalDate的最后一个可能的瞬间。

我的方法如下:

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));
}

我认为我还需要避免(在任何其他地方)映射"日期结束" LocalDateTime使用.AtLeniently(..),因为如果23:59:59.9999999是"跳过"并且在目标DateTimeZone中不存在,然后它将被映射到外部'外部的下一个可用时刻。差距00:00:00.000000,这将给我一个独家 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);
}

1 个答案:

答案 0 :(得分:5)

首先,正如评论中所述,只要你可以使用独占上限,这将是一个好主意:)

我的AtEndOfDay方法看起来很合理,除了我使用Duration.Epsilon代替Duration.FromTicks。特别是,在Noda Time 2.0中,我们将转向精确到纳秒而不是刻度; Duration.Epsilon会在两种情况下都做你想做的事。

对于LocalDate解决方案,在我看来,我们错过了LocalTime.MaxValue(或EndOfDay)的值,这是最大的可表示LocalTime。如果可以,你可以写:

return date.At(LocalTime.MaxValue);

会删除相同的" ticks"问题和以前一样。我会尝试记住将其添加到2.0中 - 尽管它会记录下来并对#34的效果进行评论;只有在您被旧系统强制使用时才会使用此功能。 :)

添加一天然后减去刻度(或纳秒)的一个缺点是它会在LocalDate.MaxValue上失败。这可能不是实际问题,但对于Noda Time本身的代码,我们会尽量避免这样的事情。我不会试图为ZonedDateTime版本避免它,因为它是一个相当复杂的场景。 (有可能这样做,但它不值得。)