Jawaban:
DateTime RoundUp(DateTime dt, TimeSpan d)
{
return new DateTime((dt.Ticks + d.Ticks - 1) / d.Ticks * d.Ticks, dt.Kind);
}
Contoh:
var dt1 = RoundUp(DateTime.Parse("2011-08-11 16:59"), TimeSpan.FromMinutes(15));
// dt1 == {11/08/2011 17:00:00}
var dt2 = RoundUp(DateTime.Parse("2011-08-11 17:00"), TimeSpan.FromMinutes(15));
// dt2 == {11/08/2011 17:00:00}
var dt3 = RoundUp(DateTime.Parse("2011-08-11 17:01"), TimeSpan.FromMinutes(15));
// dt3 == {11/08/2011 17:15:00}
DateTime RoundUp(DateTime dt, TimeSpan d) { return new DateTime(((dt.Ticks + d.Ticks - 1) / d.Ticks) * d.Ticks, dt.Kind); }
Datang dengan solusi yang tidak melibatkan mengalikan dan membagi long
angka.
public static DateTime RoundUp(this DateTime dt, TimeSpan d)
{
var modTicks = dt.Ticks % d.Ticks;
var delta = modTicks != 0 ? d.Ticks - modTicks : 0;
return new DateTime(dt.Ticks + delta, dt.Kind);
}
public static DateTime RoundDown(this DateTime dt, TimeSpan d)
{
var delta = dt.Ticks % d.Ticks;
return new DateTime(dt.Ticks - delta, dt.Kind);
}
public static DateTime RoundToNearest(this DateTime dt, TimeSpan d)
{
var delta = dt.Ticks % d.Ticks;
bool roundUp = delta > d.Ticks / 2;
var offset = roundUp ? d.Ticks : 0;
return new DateTime(dt.Ticks + offset - delta, dt.Kind);
}
Pemakaian:
var date = new DateTime(2010, 02, 05, 10, 35, 25, 450); // 2010/02/05 10:35:25
var roundedUp = date.RoundUp(TimeSpan.FromMinutes(15)); // 2010/02/05 10:45:00
var roundedDown = date.RoundDown(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00
var roundedToNearest = date.RoundToNearest(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00
%d.Ticks
di RoundUp
diperlukan? d.Ticks - (dt.Ticks % d.Ticks))
akan selalu kurang dari d.Ticks
, jadi jawabannya harus sama benar?
jika Anda perlu membulatkan ke interval waktu terdekat (tidak naik) maka saya sarankan untuk menggunakan yang berikut
static DateTime RoundToNearestInterval(DateTime dt, TimeSpan d)
{
int f=0;
double m = (double)(dt.Ticks % d.Ticks) / d.Ticks;
if (m >= 0.5)
f=1;
return new DateTime(((dt.Ticks/ d.Ticks)+f) * d.Ticks);
}
void Main()
{
var date1 = new DateTime(2011, 8, 11, 16, 59, 00);
date1.Round15().Dump();
var date2 = new DateTime(2011, 8, 11, 17, 00, 02);
date2.Round15().Dump();
var date3 = new DateTime(2011, 8, 11, 17, 01, 23);
date3.Round15().Dump();
var date4 = new DateTime(2011, 8, 11, 17, 00, 00);
date4.Round15().Dump();
}
public static class Extentions
{
public static DateTime Round15(this DateTime value)
{
var ticksIn15Mins = TimeSpan.FromMinutes(15).Ticks;
return (value.Ticks % ticksIn15Mins == 0) ? value : new DateTime((value.Ticks / ticksIn15Mins + 1) * ticksIn15Mins);
}
}
Hasil:
8/11/2011 5:00:00 PM
8/11/2011 5:15:00 PM
8/11/2011 5:15:00 PM
8/11/2011 5:00:00 PM
2011-08-11 17:00:01
akan terpotong ke2011-08-11 17:00:00
Karena saya benci menciptakan kembali roda, saya mungkin akan mengikuti algoritma ini untuk membulatkan nilai DateTime ke peningkatan waktu tertentu (Timespan):
DateTime
nilai untuk dibulatkan menjadi nilai floating-point desimal yang mewakili jumlah keseluruhan dan fraksional TimeSpan
unit.Math.Round()
.TimeSpan
unit.DateTime
nilai baru dari jumlah kutu bulat dan kembalikan ke pemanggil.Berikut kodenya:
public static class DateTimeExtensions
{
public static DateTime Round( this DateTime value , TimeSpan unit )
{
return Round( value , unit , default(MidpointRounding) ) ;
}
public static DateTime Round( this DateTime value , TimeSpan unit , MidpointRounding style )
{
if ( unit <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("unit" , "value must be positive") ;
Decimal units = (decimal) value.Ticks / (decimal) unit.Ticks ;
Decimal roundedUnits = Math.Round( units , style ) ;
long roundedTicks = (long) roundedUnits * unit.Ticks ;
DateTime instance = new DateTime( roundedTicks ) ;
return instance ;
}
}
DateTime
, tapi saya juga ingin kemampuan untuk putaran sampai ke kelipatan unit
. Melewati MidpointRounding.AwayFromZero
ke Round
tidak memiliki efek yang diinginkan. Apakah Anda memikirkan hal lain dengan menerima MidpointRounding
argumen?
Versi saya
DateTime newDateTimeObject = oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15);
Sebagai metode itu akan mengunci seperti ini
public static DateTime GetNextQuarterHour(DateTime oldDateTimeObject)
{
return oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15);
}
dan disebut seperti itu
DateTime thisIsNow = DateTime.Now;
DateTime nextQuarterHour = GetNextQuarterHour(thisIsNow);
Perhatian: rumus di atas salah, yaitu yang berikut:
DateTime RoundUp(DateTime dt, TimeSpan d)
{
return new DateTime(((dt.Ticks + d.Ticks - 1) / d.Ticks) * d.Ticks);
}
harus ditulis ulang sebagai:
DateTime RoundUp(DateTime dt, TimeSpan d)
{
return new DateTime(((dt.Ticks + d.Ticks/2) / d.Ticks) * d.Ticks);
}
/ d.Ticks
membulatkan ke interval 15 menit terdekat (sebut saja "blok" ini), menambahkan hanya setengah blok tidak menjamin pembulatan ke atas. Pertimbangkan kapan Anda memiliki 4,25 blok. Jika Anda menambahkan 0,5 blok, lalu menguji berapa banyak blok bilangan bulat yang Anda miliki, Anda masih memiliki 4. Menambahkan satu centang kurang dari satu blok penuh adalah tindakan yang benar. Ini memastikan Anda selalu naik ke kisaran blok berikutnya (sebelum pembulatan ke bawah), tetapi mencegah Anda bergerak di antara blok yang tepat. (Yaitu, jika Anda menambahkan satu blok penuh ke 4.0 blok, 5.0 akan membulatkan menjadi 5, ketika Anda menginginkan 4. 4.99 akan menjadi 4.)
Solusi yang lebih verbose, yang menggunakan modulo dan menghindari perhitungan yang tidak perlu.
public static class DateTimeExtensions
{
public static DateTime RoundUp(this DateTime dt, TimeSpan ts)
{
return Round(dt, ts, true);
}
public static DateTime RoundDown(this DateTime dt, TimeSpan ts)
{
return Round(dt, ts, false);
}
private static DateTime Round(DateTime dt, TimeSpan ts, bool up)
{
var remainder = dt.Ticks % ts.Ticks;
if (remainder == 0)
{
return dt;
}
long delta;
if (up)
{
delta = ts.Ticks - remainder;
}
else
{
delta = -remainder;
}
return dt.AddTicks(delta);
}
}
Ini adalah solusi sederhana untuk mengumpulkan hingga 1 menit terdekat. Ini menjaga informasi TimeZone dan Jenis DateTime. Ini dapat dimodifikasi agar sesuai dengan kebutuhan Anda lebih lanjut (jika Anda perlu membulatkan ke 5 menit terdekat, dll).
DateTime dbNowExact = DateTime.Now;
DateTime dbNowRound1 = (dbNowExact.Millisecond == 0 ? dbNowExact : dbNowExact.AddMilliseconds(1000 - dbNowExact.Millisecond));
DateTime dbNowRound2 = (dbNowRound1.Second == 0 ? dbNowRound1 : dbNowRound1.AddSeconds(60 - dbNowRound1.Second));
DateTime dbNow = dbNowRound2;
Anda dapat menggunakan metode ini, ia menggunakan tanggal yang ditentukan untuk memastikan ia mempertahankan segala jenis globalisasi dan datetime yang sebelumnya ditentukan dalam objek datetime.
const long LNG_OneMinuteInTicks = 600000000;
/// <summary>
/// Round the datetime to the nearest minute
/// </summary>
/// <param name = "dateTime"></param>
/// <param name = "numberMinutes">The number minute use to round the time to</param>
/// <returns></returns>
public static DateTime Round(DateTime dateTime, int numberMinutes = 1)
{
long roundedMinutesInTicks = LNG_OneMinuteInTicks * numberMinutes;
long remainderTicks = dateTime.Ticks % roundedMinutesInTicks;
if (remainderTicks < roundedMinutesInTicks / 2)
{
// round down
return dateTime.AddTicks(-remainderTicks);
}
// round up
return dateTime.AddTicks(roundedMinutesInTicks - remainderTicks);
}
Jika Anda ingin menggunakan TimeSpan untuk membulatkan, Anda dapat menggunakan ini.
/// <summary>
/// Round the datetime
/// </summary>
/// <example>Round(dt, TimeSpan.FromMinutes(5)); => round the time to the nearest 5 minutes.</example>
/// <param name = "dateTime"></param>
/// <param name = "roundBy">The time use to round the time to</param>
/// <returns></returns>
public static DateTime Round(DateTime dateTime, TimeSpan roundBy)
{
long remainderTicks = dateTime.Ticks % roundBy.Ticks;
if (remainderTicks < roundBy.Ticks / 2)
{
// round down
return dateTime.AddTicks(-remainderTicks);
}
// round up
return dateTime.AddTicks(roundBy.Ticks - remainderTicks);
}
var d = new DateTime(2019, 04, 15, 9, 40, 0, 0);
// seharusnya 9:42 tetapi tidak satupun dari metode ini bekerja seperti itu?