Noda时间-带区域的一天的开始/结束时间



获取ZonedDateTime(s)的正确且更简洁的方法是什么?ZonedDateTime表示代码运行系统上设置的时区中当前日期的开始和结束?

下面的代码不是太复杂了吗?

ZonedDateTime nowInZone = SystemClock.Instance.Now.InZone(DateTimeZoneProviders.Bcl.GetSystemDefault());
ZonedDateTime start = new LocalDateTime(nowInZone.Year, nowInZone.Month, nowInZone.Day, 0, 0, 0).InZoneStrictly(DateTimeZoneProviders.Bcl.GetSystemDefault());
ZonedDateTime end = new LocalDateTime(nowInZone.Year, nowInZone.Month, nowInZone.Day, 23, 59, 59).InZoneStrictly(DateTimeZoneProviders.Bcl.GetSystemDefault());

给定这些值,我需要测试它们之间是否有另一个ZonedDateTime。

DateTimeZone对象上的AtStartOfDay值具有您想要的魔力。

// Get the current time
IClock systemClock = SystemClock.Instance;
Instant now = systemClock.Now;
// Get the local time zone, and the current date
DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
LocalDate today = now.InZone(tz).Date;
// Get the start of the day, and the start of the next day as the end date
ZonedDateTime dayStart = tz.AtStartOfDay(today);
ZonedDateTime dayEnd = tz.AtStartOfDay(today.PlusDays(1));
// Compare instants using inclusive start and exclusive end
ZonedDateTime other = new ZonedDateTime(); // some other value
bool between = dayStart.ToInstant() <= other.ToInstant() &&
               dayEnd.ToInstant() > other.ToInstant();

几点:

  • 最好养成将时钟实例与对Now的调用分离的习惯。这使得以后在单元测试时更容易更换时钟。

  • 您只需要获取一次本地时区。我更喜欢使用Tzdb提供程序,但任何一个提供程序都可以用于此目的。

  • 对于一天的结束,最好使用第二天的开始。这可以避免您不得不处理粒度问题,例如是否应该采用23:59、23:59:59、23:59.999、23:59:59.9999999等。此外,它还可以使计算数学时更容易获得整数结果。

    通常,日期+时间范围(或仅时间范围)应视为半开放区间[start,end),而仅日期范围应视为全封闭区间[start,end]

  • 因此,将开始与<=进行比较,但将结束与>进行比较。

  • 如果您确信另一个ZonedDateTime值位于同一时区并使用同一日历,则可以省略对ToInstant的调用,直接进行比较。

更新

正如Jon在评论中提到的,Interval类型可能是实现此目的的一个有用便利。它已经设置为使用半开放范围的Instant值。以下函数将获取特定时区中当前"一天"的间隔:

public Interval GetTodaysInterval(IClock clock, DateTimeZone timeZone)
{
    LocalDate today = clock.Now.InZone(timeZone).Date;
    ZonedDateTime dayStart = timeZone.AtStartOfDay(today);
    ZonedDateTime dayEnd = timeZone.AtStartOfDay(today.PlusDays(1));
    return new Interval(dayStart.ToInstant(), dayEnd.ToInstant());
}

这样称呼它(使用上面相同的值):

Interval day = GetTodaysInterval(systemClock, tz);

现在可以使用Contains功能进行比较:

bool between = day.Contains(other.ToInstant());

请注意,您仍然必须转换为Instant,因为Interval类型不支持时区。

相关内容

  • 没有找到相关文章

最新更新