Membulatkan objek DateTime


105

Saya ingin membulatkan tanggal / waktu ke interval terdekat untuk aplikasi charting. Saya ingin tanda tangan metode ekstensi seperti berikut sehingga pembulatan dapat dicapai untuk tingkat akurasi apa pun:

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

Idenya adalah jika saya lewat dalam rentang waktu sepuluh menit, itu akan membulatkan ke interval sepuluh menit terdekat. Saya tidak bisa memahami penerapannya dan saya berharap salah satu dari Anda akan menulis atau menggunakan sesuatu yang serupa sebelumnya.

Saya pikir baik lantai, langit-langit atau implementasi terdekat baik-baik saja.

Ada ide?

Sunting: Berkat @tvanfosson & @ShuggyCoUk, implementasinya terlihat seperti ini:

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

Dan disebut seperti itu:

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

Bersulang!


1
Beberapa implementasi di sini mungkin juga membantu: stackoverflow.com/questions/766626/…
Matt Hamilton


3
Jangan lupa untuk menambahkan DateTimeKind asli ke tanggal yang baru dibuat misalnya: DateTime baru (centang * span.Ticks, date.Kind);
AM

Jawaban:


130

Lantai

long ticks = date.Ticks / span.Ticks;

return new DateTime( ticks * span.Ticks );

Round (naik di titik tengah)

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

return new DateTime( ticks * span.Ticks );

Plafon

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

return new DateTime( ticks * span.Ticks );

5
Saya baru-baru ini mengalami masalah saat DateTimeKind tidak disimpan. Perubahan berikut ke baris terakhir di setiap metode membantu dalam kasus saya:return new DateTime(ticks * span.Ticks, date.Kind);
Peet

39

Ini akan memungkinkan Anda membulatkan ke interval apa pun yang diberikan. Ini juga sedikit lebih cepat daripada membagi dan kemudian mengalikan kutu.

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

Anda juga harus jelas jika ingin pembulatan Anda menjadi:

  1. menjadi awal, akhir atau tengah interval
    • start adalah yang termudah dan seringkali diharapkan tetapi Anda harus jelas dalam spesifikasi awal Anda.
  2. Bagaimana Anda ingin kasus batas dibulatkan.
    • biasanya hanya menjadi masalah jika Anda membulatkan ke tengah daripada akhir.
    • Karena pembulatan ke tengah adalah upaya untuk jawaban bebas bias, Anda perlu menggunakan sesuatu seperti Bankers Rounding secara teknis membulatkan setengah bahkan untuk benar-benar bebas dari bias.

Sangat mungkin bahwa Anda benar-benar hanya peduli tentang poin pertama tetapi dalam pertanyaan 'sederhana' ini perilaku yang dihasilkan dapat memiliki konsekuensi yang luas saat Anda menggunakannya di dunia nyata (sering kali pada interval yang berdekatan dengan nol)

solusi tvanfosson mencakup semua kasus yang tercantum di 1. Contoh titik tengah bias ke atas. Diragukan bahwa ini akan menjadi masalah dalam pembulatan terkait waktu.


3

Cukup gunakan Ticks, gunakan itu untuk membagi, floor / ceil / round nilainya, dan kalikan kembali.


-2

Jika Anda hanya ingin membulatkan Jam ke Nilai Plafon

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

OP meminta DateTime sebagai objek kembali.
aj.toulan
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.