はじめに 「月初取得」は“集計と締め処理のスタート地点”
業務システムで「今月分の売上」「今月の勤務時間」「請求書の対象期間」などを扱うとき、
必ずと言っていいほど出てくるのが「月初(その月の1日)」です。
「ある日付が属する月の月初を求める」
「今月の月初」「先月の月初」「来月の月初」
これをサッと出せるユーティリティを持っていると、集計系・締め処理系のコードが一気に読みやすくなります。
C# では、DateTime の「年」と「月」だけを使って new DateTime(year, month, 1) を作る、というシンプルな考え方で実現できます。
基本の考え方:年と月から「1日」を作る
どんな日付でも「その月の1日」にそろえる
まずは、ある DateTime が与えられたときに、
「その日付が属する月の月初」を求める一番基本的な方法です。
using System;
DateTime any = new DateTime(2026, 2, 10, 15, 30, 0); // 2026/02/10 15:30
DateTime monthStart = new DateTime(any.Year, any.Month, 1);
Console.WriteLine(any); // 2026/02/10 15:30:00
Console.WriteLine(monthStart); // 2026/02/01 0:00:00
C#ポイントは、any.Year と any.Month をそのまま使い、
日付だけ 1 に固定して new DateTime(year, month, 1) を作ることです。
これで「その月の1日 0:00:00」の DateTime が得られます。
時刻部分は 0:00:00 にリセットされるので、
「日付だけを見たい」集計処理などにはちょうどよい形になります。
ユーティリティメソッドとしての「月初取得」
任意の日付から月初を求めるメソッド
毎回 new DateTime(d.Year, d.Month, 1) と書くのも悪くはないですが、
「これは月初を取っているんだ」と一目で分かるように、
ユーティリティメソッドにしてしまうのがおすすめです。
public static class MonthUtil
{
public static DateTime GetMonthStart(DateTime date)
{
return new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind);
}
}
C#ここでは、あえて時刻と Kind(Local / Utc / Unspecified)も引き継いでいます。
「日付だけ 1 日にそろえ、時刻と時間軸はそのまま」という方針です。
もし「必ず 0:00:00 にしたい」なら、もっとシンプルにしても構いません。
public static DateTime GetMonthStart(DateTime date)
{
return new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind);
}
C#使い方はとても直感的です。
DateTime d = new DateTime(2026, 2, 10, 15, 30, 0, DateTimeKind.Local);
DateTime monthStart = MonthUtil.GetMonthStart(d);
Console.WriteLine(monthStart); // 2026/02/01 0:00:00 (Local)
C#「このメソッドを通せば月初が返ってくる」という約束がコード上に見えるのが大事です。
「今月」「先月」「来月」の月初を取る
今月の月初
今月の月初は、DateTime.Today(今日の日付、時刻は 0:00)を使うと分かりやすく書けます。
DateTime today = DateTime.Today;
DateTime thisMonthStart = new DateTime(today.Year, today.Month, 1);
Console.WriteLine(today); // 2026/02/10 0:00:00 など
Console.WriteLine(thisMonthStart); // 2026/02/01 0:00:00
C#ユーティリティにまとめるとこうなります。
public static class MonthUtil
{
public static DateTime GetThisMonthStartLocal()
{
DateTime today = DateTime.Today; // Local, 時刻0:00
return new DateTime(today.Year, today.Month, 1, 0, 0, 0, DateTimeKind.Local);
}
}
C#先月の月初・来月の月初
「先月」「来月」は、AddMonths を組み合わせるときれいに書けます。
public static class MonthUtil
{
public static DateTime GetThisMonthStartLocal()
{
DateTime today = DateTime.Today;
return new DateTime(today.Year, today.Month, 1, 0, 0, 0, DateTimeKind.Local);
}
public static DateTime GetNextMonthStartLocal()
{
DateTime thisMonthStart = GetThisMonthStartLocal();
return thisMonthStart.AddMonths(1);
}
public static DateTime GetPreviousMonthStartLocal()
{
DateTime thisMonthStart = GetThisMonthStartLocal();
return thisMonthStart.AddMonths(-1);
}
}
C#使い方の例です。
DateTime thisMonth = MonthUtil.GetThisMonthStartLocal();
DateTime nextMonth = MonthUtil.GetNextMonthStartLocal();
DateTime prevMonth = MonthUtil.GetPreviousMonthStartLocal();
Console.WriteLine(thisMonth); // 2026/02/01 0:00:00
Console.WriteLine(nextMonth); // 2026/03/01 0:00:00
Console.WriteLine(prevMonth); // 2026/01/01 0:00:00
C#「今月の月初を基準に、AddMonths(±1) でずらす」というパターンを覚えておくと、
月単位の期間計算がとても書きやすくなります。
月初とセットでよく使う「月末取得」
月末は「翌月の月初 − 1日」で求める
月初ユーティリティを作ると、
ほぼ必ず「月末も欲しい」という話になります。
月末は、「翌月の月初から1日引く」という考え方で求めるのが定番です。
public static class MonthUtil
{
public static DateTime GetMonthStart(DateTime date)
{
return new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind);
}
public static DateTime GetMonthEnd(DateTime date)
{
DateTime monthStart = GetMonthStart(date);
DateTime nextMonthStart = monthStart.AddMonths(1);
return nextMonthStart.AddDays(-1);
}
}
C#使い方の例です。
DateTime d = new DateTime(2026, 2, 10);
DateTime monthStart = MonthUtil.GetMonthStart(d);
DateTime monthEnd = MonthUtil.GetMonthEnd(d);
Console.WriteLine(monthStart); // 2026/02/01
Console.WriteLine(monthEnd); // 2026/02/28(うるう年でなければ)
C#「月初を取る → 翌月の月初を取る → 1日戻す」という流れにしておくと、
2月やうるう年も含めて、すべての月で正しい月末が求められます。
月初ユーティリティを軸に、月末も一緒に設計しておくと、
月次集計や締め処理のコードがとてもスッキリします。
UTCとローカル、どちらの月初を扱うか
内部処理はUTC、表示はローカル、月初はどっち基準?
日時処理全般と同じく、月初取得でも
「UTC基準なのか、ローカル(例えば日本時間)基準なのか」を意識する必要があります。
例えば、「日本時間での今月の月初」を求めたい場合は、
まず UTC から日本時間に変換してから月初を取る、という流れになります。
using System;
public static class MonthUtil
{
public static DateTime GetThisMonthStartJstFromUtcNow()
{
DateTime utcNow = DateTime.UtcNow;
TimeZoneInfo jst = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");
DateTime nowJst = TimeZoneInfo.ConvertTimeFromUtc(utcNow, jst);
DateTime monthStartJst = new DateTime(nowJst.Year, nowJst.Month, 1, 0, 0, 0, DateTimeKind.Unspecified);
return monthStartJst;
}
}
C#「どのタイムゾーンの“月初”なのか」を要件として決めておき、
ユーティリティの名前やコメントにもそれを反映しておくと、
後から読んだときに迷いにくくなります。
まとめ 「月初取得ユーティリティ」は“月次ロジックの基準点”
月初取得は、
売上集計、勤怠集計、請求締め、サブスク更新など、
月次ロジックのほぼすべてのスタート地点になります。
押さえておきたいポイントは、次のようなイメージです。
任意の日付の月初は new DateTime(date.Year, date.Month, 1, …) で作れる。
「今月」「先月」「来月」の月初は、「今月の月初」を基準に AddMonths(±1) でずらすときれいに書ける。
月末は「翌月の月初 − 1日」で求めると、全ての月で正しく計算できる。
UTC基準かローカル基準か(どのタイムゾーンの月初か)を意識し、ユーティリティ名にもそれを反映しておくと安全。
このあたりをきちんと押さえておくと、
「その場しのぎで日付をいじっている」状態から一歩進んで、
“月次処理の基準点をきれいに定義した、実務で使える日付ユーティリティ”を
自分のC#コードの中に自然に組み込めるようになります。
