はじめに 「日付丸め」は“時間をざっくり区切るための技”
「集計は1時間単位で」「グラフは5分刻みで」「日付だけにそろえたい」
こういう“きっちりした時刻”ではなく“区切りの時刻”が欲しいときに必要になるのが「日付丸め」です。
C# には「丸め専用メソッド」はありませんが、DateTime と TimeSpan を組み合わせることで、
「切り捨て」「切り上げ」「四捨五入」を自分で自由に作れます。
ここでは、
まず「日付だけにそろえる」「時刻を0分0秒にそろえる」といった基本から、
「5分単位」「15分単位」「日単位・月単位の丸め」、
そして“切り捨て・切り上げ・四捨五入”の違いまで、
初心者向けにかみ砕いて説明していきます。
一番基本の丸め:日付だけにそろえる(時刻を消す)
.Date と DateTime.Today の意味
「時刻はいらないから“日付だけ”にしたい」という場面はとても多いです。
このときに使うのが DateTime.Date プロパティです。
DateTime dt = new DateTime(2026, 2, 18, 20, 45, 30);
DateTime onlyDate = dt.Date;
Console.WriteLine(dt); // 2026/02/18 20:45:30
Console.WriteLine(onlyDate); // 2026/02/18 0:00:00
C#dt.Date は、「その日の 0:00:00 にそろえた DateTime」を返します。
これは「日付単位への切り捨て」と考えてOKです。
今日の日付だけが欲しいときは DateTime.Today が使えます。
DateTime today = DateTime.Today; // 今日の 0:00:00
C#ここでの重要ポイントは、
「日付だけで比較・集計したいときは、必ず .Date で丸めてから使う」
という習慣をつけることです。
これを忘れると、「同じ日なのに違う」と判定されるバグが生まれます。
時刻の丸め:分・秒・ミリ秒を切り捨てる
「時刻はそのまま、分以下を0にしたい」
例えば、「20:45:30 を 20:00:00 にしたい(時間単位にそろえたい)」
というような“時刻の丸め”もよく出てきます。
まずは「分以下を切り捨てる」例です。
public static DateTime TruncateToHour(DateTime dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0, dt.Kind);
}
C#使い方の例です。
DateTime dt = new DateTime(2026, 2, 18, 20, 45, 30);
DateTime truncated = TruncateToHour(dt);
Console.WriteLine(truncated); // 2026/02/18 20:00:00
C#同じように、「秒以下を切り捨てる」ならこう書けます。
public static DateTime TruncateToMinute(DateTime dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0, dt.Kind);
}
C#ここでの重要ポイントは、
「new DateTime(...) で必要な部分だけ残し、残りを0にする」
というパターンを覚えることです。
これが“時刻の丸め(切り捨て)”の基本形になります。
任意の間隔への丸め:5分単位・15分単位など
考え方のコアは「TimeSpan で割って、掛け直す」
「5分単位に丸めたい」「15分単位に丸めたい」
というときは、TimeSpan を使って「割る→掛ける」という考え方をします。
まずは「切り捨て(floor)」から。
public static DateTime Floor(DateTime dt, TimeSpan interval)
{
long ticks = dt.Ticks / interval.Ticks * interval.Ticks;
return new DateTime(ticks, dt.Kind);
}
C#使い方の例です(5分単位に切り捨て)。
DateTime dt = new DateTime(2026, 2, 18, 20, 07, 30); // 20:07:30
DateTime floored = Floor(dt, TimeSpan.FromMinutes(5));
Console.WriteLine(floored); // 2026/02/18 20:05:00
C#やっていることを分解すると、
interval(ここでは5分)のTicksを使って「何個分か」を計算する- 小数点以下を切り捨てる(整数除算)
- もう一度
interval.Ticksを掛けて「丸めた時刻のTicks」を作る
という流れです。
同じ考え方で、「切り上げ(ceiling)」も作れます。
public static DateTime Ceiling(DateTime dt, TimeSpan interval)
{
long ticks = (dt.Ticks + interval.Ticks - 1) / interval.Ticks * interval.Ticks;
return new DateTime(ticks, dt.Kind);
}
C#使い方の例です(5分単位に切り上げ)。
DateTime dt = new DateTime(2026, 2, 18, 20, 07, 30); // 20:07:30
DateTime ceiled = Ceiling(dt, TimeSpan.FromMinutes(5));
Console.WriteLine(ceiled); // 2026/02/18 20:10:00
C#さらに、「四捨五入(round)」も作れます。
public static DateTime Round(DateTime dt, TimeSpan interval)
{
long halfTicks = (interval.Ticks + 1) / 2;
long ticks = (dt.Ticks + halfTicks) / interval.Ticks * interval.Ticks;
return new DateTime(ticks, dt.Kind);
}
C#使い方の例です(5分単位に四捨五入)。
DateTime dt1 = new DateTime(2026, 2, 18, 20, 07, 29); // 20:07:29 → 20:05
DateTime dt2 = new DateTime(2026, 2, 18, 20, 07, 31); // 20:07:31 → 20:10
Console.WriteLine(Round(dt1, TimeSpan.FromMinutes(5)));
Console.WriteLine(Round(dt2, TimeSpan.FromMinutes(5)));
C#ここでの重要ポイントは、
「丸めの本質は“Ticks を interval で割って、掛け直す”」
というところです。
このパターンさえ分かれば、5分でも15分でも30秒でも、好きな単位に丸められます。
日単位・月単位の丸め:日付の“始まり”と“終わり”
日の始まり・終わりにそろえる
「その日の始まり(0:00:00)」や「その日の終わり(23:59:59.999…)」にそろえたい
という場面もよくあります。
日の始まりは .Date でOKです。
public static DateTime StartOfDay(DateTime dt)
{
return dt.Date;
}
C#日の終わりは、「翌日の0時から1ティック引く」という考え方が安全です。
public static DateTime EndOfDay(DateTime dt)
{
DateTime nextDay = dt.Date.AddDays(1);
return nextDay.AddTicks(-1);
}
C#使い方の例です。
DateTime dt = new DateTime(2026, 2, 18, 20, 45, 30);
Console.WriteLine(StartOfDay(dt)); // 2026/02/18 0:00:00
Console.WriteLine(EndOfDay(dt)); // 2026/02/18 23:59:59.9999999
C#月の始まり・終わりにそろえる
月単位の丸めもよく使います。
「その月の1日」「その月の末日」にそろえるイメージです。
public static DateTime StartOfMonth(DateTime dt)
{
return new DateTime(dt.Year, dt.Month, 1, 0, 0, 0, dt.Kind);
}
public static DateTime EndOfMonth(DateTime dt)
{
DateTime firstOfNextMonth = new DateTime(dt.Year, dt.Month, 1, 0, 0, 0, dt.Kind)
.AddMonths(1);
return firstOfNextMonth.AddTicks(-1);
}
C#使い方の例です。
DateTime dt = new DateTime(2024, 2, 15, 10, 0, 0); // うるう年の2月
Console.WriteLine(StartOfMonth(dt)); // 2024/02/01 0:00:00
Console.WriteLine(EndOfMonth(dt)); // 2024/02/29 23:59:59.9999999
C#ここでの重要ポイントは、
「終わりは“次の単位の始まりから1ティック引く”」
というパターンです。
これを覚えておくと、日・月・年など、いろいろな“終わり”を安全に表現できます。
「切り捨て」「切り上げ」「四捨五入」の違いを意識する
どれを使うかで結果が変わる
丸めには大きく3種類あります。
切り捨て(floor)
切り上げ(ceiling)
四捨五入(round)
例えば「5分単位」で考えると、
20:07 を切り捨て → 20:05
20:07 を切り上げ → 20:10
20:07 を四捨五入 → 20:05(2分差なので下へ)
20:08 を切り捨て → 20:05
20:08 を切り上げ → 20:10
20:08 を四捨五入 → 20:10(3分差なので上へ)
というように、同じ元の時刻でも結果が変わります。
実務では、「どの丸め方が正しいか」は要件次第です。
勤怠の打刻 → 切り捨てか切り上げかで給与が変わる
グラフの表示軸 → 四捨五入のほうが見た目が自然なことが多い
ログのバケット分け → 切り捨てで“属する区間”を決めることが多い
など、「何のために丸めるのか」を考えて選ぶ必要があります。
ユーティリティとしては、Floor / Ceiling / Round をそれぞれ用意しておき、
呼び出し側が明示的に選べるようにしておくのが安全です。
実務での注意点:Kind とタイムゾーンを壊さない
DateTimeKind を引き継ぐことの意味
DateTime には Kind(Unspecified / Local / Utc)があります。
丸めるときに new DateTime(...) を使うと、
何も考えないと Kind が Unspecified になってしまいます。
さきほどの例では、new DateTime(..., dt.Kind) のように、元の Kind を引き継ぐようにしていました。
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0, dt.Kind);
C#これを忘れると、
UTC のつもりだった日時が「Kind 不明」になり、
後で ToLocalTime や ToUniversalTime を呼んだときにおかしな変換が起きる
といった事故につながります。
丸めユーティリティを書くときは、
「Kind を必ず引き継ぐ」というルールを徹底しておくと安心です。
まとめ 「日付丸めユーティリティ」は“時間の解像度を落とすための道具”
日付丸めは、一見ただの「0にそろえる」処理ですが、
日付だけの比較、時間単位の集計、5分刻みのグラフ、日・月・年の境界など、
業務システムのあちこちで使われる“時間の解像度を落とす技”です。
押さえておきたいポイントを整理すると、こうなります。
日付だけにそろえたいときは .Date(=日単位への切り捨て)を使う。
時刻の丸めは「必要な部分だけ残して0にする」か、「Ticks を interval で割って掛け直す」パターンで書く。
任意の間隔(5分・15分など)への丸めは、TimeSpan を使った Floor / Ceiling / Round を用意しておくと再利用しやすい。
日・月・年の“終わり”は「次の単位の始まりから1ティック引く」という形で安全に表現できる。DateTimeKind を引き継ぐことと、「切り捨て/切り上げ/四捨五入」の違いを意識して選ぶことが、実務ではとても重要になる。
ここまで押さえておけば、
「なんとなく時刻をいじっている」状態から一歩進んで、
“ビジネスの時間軸をきれいに区切れる、実務で使える日付丸めユーティリティ”を
自分の C# コードの中に自信を持って組み込めるようになります。

