Как вы округляете время до ближайшего, но также меняете дату в настройке NodaTime? - PullRequest
0 голосов
/ 20 мая 2019

Мне нужно округлить различные объекты 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, и округляется до полуночи, кажется, простого способа изменить дату вперед не представляется возможным. Я подумал о том, чтобы сделать второй регулятор, чтобы скорректировать дату вперед, но я не знаю, округлю ли я вверх или вверх, или нужно ли его корректировать вперед.

Я что-то упустил?

Edit: Я пытаюсь создать и использовать TimeAdjusters в NodaTime, которые работают как встроенные, как определено здесь .

Если вы создадите такой как этот

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)

1 Ответ

1 голос
/ 20 мая 2019

Я не совсем уверен, правильно ли я вас понял, но я бы подошел к этому примерно так:

    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
...