Làm tròn các đối tượng DateTime


105

Tôi muốn làm tròn ngày / giờ thành khoảng thời gian gần nhất cho một ứng dụng biểu đồ. Tôi muốn một chữ ký của phương thức mở rộng như sau để việc làm tròn có thể được thực hiện cho bất kỳ mức độ chính xác nào:

static DateTime Round(this DateTime date, TimeSpan span);

Ý tưởng là nếu tôi vượt qua trong khoảng thời gian mười phút, nó sẽ làm tròn đến khoảng thời gian mười phút gần nhất. Tôi không thể hiểu được việc triển khai và tôi hy vọng một trong số các bạn sẽ viết hoặc sử dụng một cái gì đó tương tự trước đây.

Tôi nghĩ rằng việc triển khai sàn, trần hoặc gần nhất đều ổn.

Bất kỳ ý tưởng?

Chỉnh sửa: Cảm ơn @tvanfosson & @ShuggyCoUk, việc triển khai trông như thế này:

public static class DateExtensions {
    public static DateTime Round(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Floor(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks / span.Ticks);
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Ceil(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + span.Ticks - 1) / span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
}

Và được gọi như vậy:

DateTime nearestHour = DateTime.Now.Round(new TimeSpan(1,0,0));
DateTime minuteCeiling = DateTime.Now.Ceil(new TimeSpan(0,1,0));
DateTime weekFloor = DateTime.Now.Floor(new TimeSpan(7,0,0,0));
...

Chúc mừng!


1
Một số trong những triển khai ở đây có thể giúp quá: stackoverflow.com/questions/766626/...
Matt Hamilton


3
Đừng quên thêm DateTimeKind ban đầu vào ngày mới tạo, ví dụ: new DateTime (tick * span.Ticks, date.Kind);
Sáng

Câu trả lời:


130

Sàn nhà

long ticks = date.Ticks / span.Ticks;

return new DateTime( ticks * span.Ticks );

Làm tròn (lên trên điểm giữa)

long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );

Trần nhà

long ticks = (date.Ticks + span.Ticks - 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );

5
Gần đây tôi đã gặp sự cố trong đó DateTimeKind không được lưu giữ. Chỉnh sửa sau đây cho dòng cuối cùng trong mỗi phương pháp đã giúp ích trong trường hợp của tôi:return new DateTime(ticks * span.Ticks, date.Kind);
Peet

39

Điều này sẽ cho phép bạn làm tròn đến bất kỳ khoảng nào đã cho. Nó cũng nhanh hơn một chút so với việc phân chia và sau đó nhân các con ve.

public static class DateTimeExtensions
{
  public static DateTime Floor(this DateTime dateTime, TimeSpan interval)
  {
    return dateTime.AddTicks(-(dateTime.Ticks % interval.Ticks));
  }

  public static DateTime Ceiling(this DateTime dateTime, TimeSpan interval)
  {
    var overflow = dateTime.Ticks % interval.Ticks;

    return overflow == 0 ? dateTime : dateTime.AddTicks(interval.Ticks - overflow);
  }

  public static DateTime Round(this DateTime dateTime, TimeSpan interval)
  {
    var halfIntervalTicks = (interval.Ticks + 1) >> 1;

    return dateTime.AddTicks(halfIntervalTicks - ((dateTime.Ticks + halfIntervalTicks) % interval.Ticks));
  }
}

11

Bạn cũng nên rõ ràng nếu bạn muốn làm tròn thành:

  1. bắt đầu, kết thúc hoặc giữa khoảng thời gian
    • bắt đầu là dễ nhất và thường là mong đợi nhưng bạn nên rõ ràng trong thông số ban đầu của mình.
  2. Làm thế nào bạn muốn các trường hợp ranh giới làm tròn.
    • thường chỉ là một vấn đề nếu bạn đang làm tròn đến phần giữa thay vì phần cuối.
    • Vì làm tròn đến giữa là một nỗ lực cho một câu trả lời không thiên vị, nên bạn cần sử dụng một cái gì đó như Kỹ thuật làm tròn của Bankers Rounding một nửa để thực sự không bị thiên vị.

Rất có thể bạn thực sự chỉ quan tâm đến điểm đầu tiên nhưng trong những câu hỏi 'đơn giản' này, hành vi kết quả có thể gây ra những hậu quả sâu rộng khi bạn sử dụng nó trong thế giới thực (thường ở những khoảng gần bằng 0)

giải pháp của tvanfosson bao gồm tất cả các trường hợp được liệt kê trong 1. Ví dụ về điểm giữa có độ lệch hướng lên trên. Có thể nghi ngờ rằng đây sẽ là một vấn đề trong việc làm tròn liên quan đến thời gian.


3

Chỉ cần sử dụng Ticks, sử dụng nó để chia, sàn / ceil / làm tròn giá trị và nhân lại.


-2

Nếu bạn chỉ muốn làm tròn Giá trị Giờ lên Giá trần

Console.WriteLine(DateTime.Now.ToString("M/d/yyyy hh:00:00"));

OP đã yêu cầu một DateTime làm đối tượng trả về.
aj.toulan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.