DateTime nesnelerini yuvarlama


105

Bir grafik uygulaması için tarihleri ​​/ saatleri en yakın aralığa yuvarlamak istiyorum. Aşağıdaki gibi bir uzatma yöntemi imzası istiyorum, böylece herhangi bir doğruluk düzeyi için yuvarlama elde edilebilir:

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

Buradaki fikir, on dakikalık bir zaman aralığında geçersem, en yakın on dakikalık aralığa yuvarlanacağıdır. Uygulama konusunda kafamı bulamıyorum ve umarım biriniz daha önce benzer bir şey yazmış veya kullanmış olacaktır.

Bir zemin, tavan veya en yakın uygulamanın iyi olduğunu düşünüyorum.

Herhangi bir fikir?

Düzenleme: @tvanfosson & @ShuggyCoUk sayesinde, uygulama şuna benzer:

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

Ve şöyle adlandırılır:

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

Şerefe!


1
Buradaki uygulamalardan bazıları da yardımcı olabilir: stackoverflow.com/questions/766626/…
Matt Hamilton


3
Orijinal DateTimeKind öğesini yeni oluşturulan tarihe eklemeyi unutmayın, örn: new DateTime (* span.Ticks, date.Kind işaretler);
AM

Yanıtlar:


130

Zemin

long ticks = date.Ticks / span.Ticks;

return new DateTime( ticks * span.Ticks );

Yuvarlama (orta noktada yukarı)

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

return new DateTime( ticks * span.Ticks );

Tavan

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

return new DateTime( ticks * span.Ticks );

5
Geçenlerde DateTimeKind'in korunmadığı bir sorunla karşılaştım. Her yöntemde son satıra yapılan aşağıdaki ince ayar benim durumumda yardımcı oldu:return new DateTime(ticks * span.Ticks, date.Kind);
Peet

39

Bu, verilen herhangi bir aralığa yuvarlamanıza izin verecektir. Ayrıca keneleri bölmekten ve sonra çarpmaktan biraz daha hızlıdır.

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

Yuvarlamanızın aşağıdakileri yapmasını istiyorsanız da net olmalısınız:

  1. aralığın başında, sonunda veya ortasında olmak
    • Başlangıç, en kolay ve genellikle beklenen olandır, ancak ilk belirtiminizde net olmalısınız.
  2. Sınır durumlarının nasıl yuvarlanmasını istediğinizi.
    • normalde yalnızca sona değil ortaya yuvarlıyorsanız sorun olur.
    • Ortaya yuvarlama, önyargısız bir cevap verme girişimi olduğundan, gerçekten önyargısız olmak için bile teknik olarak yarı yuvarlayan Bankacılar gibi bir şey kullanmanız gerekir .

Muhtemelen yalnızca ilk noktayı önemsiyorsunuzdur, ancak bu 'basit' sorularda ortaya çıkan davranış, gerçek dünyada kullandığınızda (genellikle sıfıra bitişik aralıklarla) çok geniş kapsamlı sonuçlara sahip olabilir.

tvanfosson'un çözümü 1'de listelenen tüm durumları kapsamaktadır. Orta nokta örneği yukarı doğru önyargılıdır. Bunun zamana bağlı yuvarlamada bir sorun olacağı şüphelidir.


3

Değeri bölmek, yere / tavana / yuvarlamak ve tekrar çarpmak için Keneleri kullanın.


-2

Saati Tavan Değerine yuvarlamak istiyorsanız

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

OP, dönen nesne olarak bir DateTime istedi.
aj.toulan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.