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

Noda Time - Start/end of day with zone(野田时间 - 带区域的一天的开始/结束)

本文介绍了野田时间 - 带区域的一天的开始/结束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What's the proper and more concise way to get the ZonedDateTime(s) which represent the start and the end of the current day in the timezone set on the system on which the code runs?

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

Isn't the following code too much complicated?

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.

Given those values, I need to test if another ZonedDateTime is between them.

推荐答案

DateTimeZone 对象上的 AtStartOfDay 值具有您正在寻找的魔力.

The AtStartOfDay value on the DateTimeZone object has the magic you're looking for.

// 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 的调用分开的习惯.这使得以后在单元测试时更换时钟更容易.

  • It's better to get in the habit of separating the clock instance from the call to Now. This makes it easier to replace the clock later when unit testing.

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

You only need to get the local time zone once. I prefer to use the Tzdb provider, but either provider will work for this purpose.

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

For the end of day, it's better to use the start of the next day. This prevents you from having to deal with granularity issues, such as whether you should take 23:59, 23:59:59, 23:59.999, 23:59:59.9999999, etc. Also, it makes it easier to get whole-number results when doing math.

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

In general, date+time ranges (or time-only ranges) should be treated as half-open intervals [start,end) - while date-only ranges should be treated as fully-closed intervals [start,end].

因此,开始与 <= 进行比较,而结束与 > 进行比较.

Because of this, the start is compared with <= but the end is compared with >.

如果您确定其他 ZonedDateTime 值位于同一时区并使用同一日历,则可以省略对 ToInstant 的调用并直接比较吧.

If you know for certain that the other ZonedDateTime value is in the same time zone and uses the same calendar, you can omit the calls to ToInstant and just compare them directly.

更新

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

As Jon mentioned in comments, the Interval type may be a useful convenience for this purpose. It is already set up to work with a half-open range of Instant values. The following function will get the interval for a the current "day" in a particular time zone:

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

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

Call it like this (using the same values from above):

Interval day = GetTodaysInterval(systemClock, tz);

现在可以使用 Contains 函数进行比较:

And now comparison can be done with the Contains function:

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

请注意,您仍然需要转换为 Instant,因为 Interval 类型不支持时区.

Note that you still have to convert to an Instant, as the Interval type is not time zone aware.

这篇关于野田时间 - 带区域的一天的开始/结束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:野田时间 - 带区域的一天的开始/结束

基础教程推荐