c# - 将 Nodatime 中的时间舍入到最接近的时间间隔
问题描述
我们需要将时间设置为最近的任意间隔(例如,由时间跨度或持续时间表示)。
假设我们需要将它降到最接近的十分钟。例如 13:02 变成 13:00 和 14:12 变成 14:10
如果不使用 Nodatime,您可以执行以下操作:
// Floor
long ticks = date.Ticks / span.Ticks;
return new DateTime( ticks * span.Ticks );
这将使用时间跨度的刻度将日期时间设置为特定时间。
似乎 NodaTime 暴露了一些我们以前没有考虑过的复杂性。你可以写一个这样的函数:
public static Instant FloorBy(this Instant time, Duration duration)
=> time.Minus(Duration.FromTicks(time.ToUnixTimeTicks() % duration.BclCompatibleTicks));
但这种实现似乎并不正确。“最近十分钟的地板”似乎取决于时区/时间偏移量。虽然在 UTC 中可能是 13:02,但在偏移量为 +05:45 的尼泊尔,时间将是 18:47。
这意味着在 UTC 中,精确到十分钟意味着减去两分钟,而在尼泊尔,这意味着减去七分钟。
我觉得我应该能够以某种方式将 ZonedDateTime 或 OffsetDateTime 舍入任意时间跨度。我可以通过编写这样的函数来接近
public static OffsetDateTime FloorToNearestTenMinutes(this OffsetDateTime time)
{
return time
.Minus(Duration.FromMinutes(time.Minute % 10))
.Minus(Duration.FromSeconds(time.Second));
}
但这不允许我指定任意持续时间,因为 OffsetDateTime 没有刻度的概念。
考虑到时区,如何以任意间隔正确舍入 Instant/ZonedDateTime/OffsetDateTime?
解决方案
对于OffsetDateTime
,我建议你写一个Func<LocalTime, LocalTime>
实际上是野田时间术语中的“调整者”。然后,您可以使用以下With
方法:
// This could be a static field somewhere - or a method, so you can use
// a method group conversion.
Func<LocalTime, LocalTime> adjuster =>
new LocalTime(time.Hour, time.Minute - time.Minute % 10, 0);
// The With method applies the adjuster to just the time portion,
// keeping the date and offset the same.
OffsetDateTime rounded = originalOffsetDateTime.With(adjuster);
请注意,这仅有效,因为您的四舍五入永远不会更改日期。如果您需要一个也可以更改日期的版本(例如,将 23:58 舍入到第二天的 00:00),那么您需要获取新版本并使用该版本和原始偏移量LocalDateTime
构建一个新版本。我们没有为此提供方便的方法,但这只是调用构造函数的问题。OffsetDateTime
LocalDateTime
ZonedDateTime
由于您给出的原因,从根本上来说更棘手。目前,尼泊尔不遵守夏令时 - 但它可能会在未来这样做。在 DST 边界附近四舍五入可能会使您进入模棱两可甚至跳过的时间。这就是为什么我们不With
为ZonedDateTime
. (在您的情况下,这不太可能,尽管从历史上看是可能的……使用日期调整器,您很容易陷入这种情况。)
你可以做的是:
- 称呼
ZonedDateTime.ToOffsetDateTime
OffsetDateTime
如上圆- 打电话
OffsetDateTime.InZone(zone)
回一个ZonedDateTime
然后,您可以检查结果的偏移量ZonedDateTime
是否与原始偏移量相同,如果您想检测奇怪的情况 - 但您需要决定如何处理它们。不过,这种行为是相当合理的——如果你从ZonedDateTime
(比如说)01:47 的时间部分开始,你会ZonedDateTime
在 7 分钟前的同一时区结束。如果在最后 7 分钟内发生转换,则可能不会是 01:40……但我怀疑您实际上不需要担心。
推荐阅读
- arrays - 如何正确设置指向包含字符的数组的指针
- asp.net - ASP.NET.VB 将 GridView 单元格值从 [1] 值更改为 [High] 值的答案
- algorithm - 如果大 O 是可加的,并且 O(A) 和 O(B) 的两个函数加在一起将是 O(A + B),那么为什么两个循环不成立呢?
- c - 如何读取 .csv 文件并将其保存到二维数组中?
- scala - Pass type identifier to static macro annotation
- wordpress - 需要“阅读更多”按钮才能在 wordpress 中填写摘录字段时显示
- javascript - 尝试根据输入是否具有文本 node.js 车把来隐藏/显示部分内容
- python - 如何获取字典值的频率并映射到所有潜在值的固定顺序?
- c# - C# System.Threading.Mutex System.Threading.Mutex.OpenExisting 方法未找到
- sql - 每行的 SQL 动态 WHERE 子句