您如何将时间四舍五入到最接近的时间,同时更改 NodaTime 调节器中的日期?

How do you round time to the nearest but also change the date in a NodaTime adjuster?

我必须将各种 LocalDateTime 和 OffsetDateTime 对象四舍五入到最近的时间段(总是分钟)。例如,如果您四舍五入到最接近的 3 分钟,9:58 将四舍五入为 9:57,而 9:59 将四舍五入为 10:00。

这可以通过这样的调节器轻松完成:

public static Func<LocalTime, LocalTime> CreateRounder(TimeSpan d) =>
    input =>
    {
        var delta = input.TickOfDay % d.Ticks;
        bool roundUp = delta > d.Ticks / 2;

        if (roundUp)
        {
            var rUpDelta = (d.Ticks - (input.TickOfDay % d.Ticks)) % d.Ticks;
            return input.PlusTicks(rUpDelta);
        }

        return input.PlusTicks(-1 * delta);
    };

但是,如果 *DateTime 对象接近午夜,比如 23:59,并且四舍五入到午夜,似乎没有 easy向前更改日期的方法。我考虑过做第二个调整器来向前调整日期,但我不知道我是向下舍入还是向上舍入,或者是否确实需要向前调整。

我是不是漏掉了什么?

编辑: 我正在尝试在 NodaTime 中创建和使用 TimeAdjusters,它们的工作方式与定义的 here.

中的构建类似

如果你像这样创建一个

public static Func<LocalDateTime, LocalDateTime> CreateRounder(TimeSpan d) =>
    input =>
    {
        var delta = input.TickOfDay % d.Ticks;
        bool roundUp = delta > d.Ticks / 2;

        if (roundUp)
        {
            var rUpDelta = (d.Ticks - (input.TickOfDay % d.Ticks)) % d.Ticks;
            return input.PlusTicks(rUpDelta);
        }

        return input.PlusTicks(-1 * delta);
    };

并像这样使用它:

var ldate1 = new LocalDateTime(2019,5,17,23,59,00);
var rounder = CreateRounder(TimeSpan.FromMinutes(3));
var roundedDate1 = ldate1.With(rounder);

您可以在第 3 行指定错误:

Cannot resolve method 'With(System.Func<NodaTime.LocalDateTime,NodaTime.LocalDateTime>)', candidates are:
  NodaTime.OffsetDateTime With(System.Func<NodaTime.LocalDate,NodaTime.LocalDate>) (in struct OffsetDateTime)
  NodaTime.OffsetDateTime With(System.Func<NodaTime.LocalTime,NodaTime.LocalTime>) (in struct OffsetDateTime)

我不太确定我是否理解正确,但我会这样处理:

    public DateTime RoundTime(DateTime input)
    {
        DateTime output = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0);
        if(input.Minute % 3 == 1)
        {
            output.AddMinutes(input.Minute - 1);
        }
        else if (input.Minute % 3 == 2)
        {
            output.AddMinutes(input.Minute + 1);
        }
        else
        {
            output.AddMinutes(input.Minute);
        }
        return output;
    }

看看这是否有帮助

编辑

您可以选择将整个内容更改为 LocalDateTime 而不是 LocalTime 吗? 它看起来像这样:

    static void Main(string[] args)
    {
        List<LocalTime> localTimes = new List<LocalTime>();
        localTimes.Add(new LocalTime(23, 57, 25));
        localTimes.Add(new LocalTime(23, 58, 25));
        localTimes.Add(new LocalTime(23, 59, 25));
        localTimes.Add(new LocalTime(11, 57, 25));
        localTimes.Add(new LocalTime(12, 58, 25));
        localTimes.Add(new LocalTime(15, 59, 25));
        IEnumerable<LocalTime> locals = localTimes.Select(CreateRounder(new TimeSpan(0, 3, 0)));
        foreach (LocalTime t in locals)
        {
            Console.WriteLine(t.Hour + ":" + t.Minute + ":" + t.Second);
        }

        List<LocalDateTime> localDateTimes = new List<LocalDateTime>();
        localDateTimes.Add(new LocalDateTime(2019, 5, 20, 23, 58, 25));
        localDateTimes.Add(new LocalDateTime(2019, 5, 20, 23, 59, 25));
        localDateTimes.Add(new LocalDateTime(2019, 5, 20, 11, 42, 25));
        localDateTimes.Add(new LocalDateTime(2019, 5, 20, 5, 58, 25));

        IEnumerable<LocalDateTime> ldt = localDateTimes.Select(CreateDateTimeRounder(new TimeSpan(0, 3, 0)));

        foreach (LocalDateTime t in ldt)
        {
            Console.WriteLine(t.Year + "-" + t.Month + "-" + t.Day + " " + t.Hour + ":" + t.Minute + ":" + t.Second);
        }
        Console.ReadLine();
    }

    public static Func<LocalTime, LocalTime> CreateRounder(TimeSpan d) =>
input =>
{
    var delta = input.TickOfDay % d.Ticks;
    bool roundUp = delta > d.Ticks / 2;

    if (roundUp)
    {
        var rUpDelta = (d.Ticks - (input.TickOfDay % d.Ticks)) % d.Ticks;
        return input.PlusTicks(rUpDelta);
    }

    return input.PlusTicks(-1 * delta);
};

    public static Func<LocalDateTime, LocalDateTime> CreateDateTimeRounder(TimeSpan d) =>
input =>
{
    var delta = input.TickOfDay % d.Ticks;
    bool roundUp = delta > d.Ticks / 2;

    if (roundUp)
    {
        var rUpDelta = (d.Ticks - (input.TickOfDay % d.Ticks)) % d.Ticks;
        return input.PlusTicks(rUpDelta);
    }

    return input.PlusTicks(-1 * delta);
};

输出结果如下:

23:57:0
23:57:0
0:0:0
11:57:0
12:57:0
16:0:0
2019-5-20 23:57:0
2019-5-21 0:0:0
2019-5-20 11:42:0
2019-5-20 5:57:0