今回は日付や時刻に関する関数をご紹介します。
日付や時刻を表す型のTDateTime型は内部的にはDouble型で、
整数部は西暦1899/12/30からの経過日数を示し、小数部はその日の経過時間を示します。
今回はTDateTimeを使った関数をご説明します。
基本的な関数
よく使われると思いますが、現在の日付・時刻(PCのシステム日付・時刻)を取得する関数には
次のようなものがあります。これらの関数はTDateTime型で返されます。
・Date関数
Date関数を使うと、端末PCの現在日付をTDateTime型として取得できます。
時刻を表す小数部は0になります。
・Now関数
グローバル関数DateとTimeにより返される値の合計に対応する、現在の日付と時刻を返します。
・Time関数とGetTime関数
端末PCの現在の時刻部分をTDateTime型で返します。
この2つの関数は完全に同じ結果を返します。日付を表す整数部は0になります。
また次のような便利な関数が用意されています。
・DayOfWeek関数
指定された日付の曜日を 1 から 7 の整数で返します。
DayOfWeekは、ISO 8601規格に準拠していません。
日曜日が 1 で、土曜日が 7 に相当します。
・DayOfTheWeek関数
指定された日付の曜日を 1 から 7 の整数で返します。
DayOfTheWeekはISO 8601規格に準拠しています。
月曜日が 1 で、日曜日が 7 に相当します。
uses節に、日付時刻を専門に扱うDateUtils(System.DateUtils)ユニットの追加が必要となります。
DayOfWeek関数とDayOfTheWeek関数では開始曜日が違います。
現在日付の曜日を文字で表す場合を次に示します。
DateUtilsユニットに含まれる曜日定数を使用すれば戻り値がわかりやすくなりますが、
曜日定数はDayOfWeek関数では使用できませんのでご注意下さい。
//(DayOfWeek関数の場合)
case DayOfWeek(Now) of
1 : Edit1.Text := '日';
2 : Edit1.Text := '月';
3 : Edit1.Text := '火';
4 : Edit1.Text := '水';
5 : Edit1.Text := '木';
6 : Edit1.Text := '金';
7 : Edit1.Text := '土';
end;
//(DayOfTheWeek関数の場合)※曜日定数を使用
case DayOfTheWeek(Now) of
DayMonday : Edit6.Text := '月'; // 1
DayTuesday : Edit6.Text := '火'; // 2
DayWednesday : Edit6.Text := '水'; // 3
DayThursday : Edit6.Text := '木'; // 4
DayFriday : Edit6.Text := '金'; // 5
DaySaturday : Edit6.Text := '土'; // 6
DaySunday : Edit6.Text := '日'; // 7
end;
・IsLeapYear関数
指定された年(Word型)がうるう年なら「True」を返します。
if IsLeapYear(2024) then
Edit2.Text := 'うるう年'
else
Edit2.Text := 'うるう年でない';
・IsInLeapYear関数(※DateUtilsユニットが必要)
指定されたTDateTime値がうるう年なら「True」を返します。
if IsInLeapYear(Now) then
Edit2.Text := 'うるう年'
else
Edit2.Text := 'うるう年でない';
日付時刻と文字列の変換に用いる関数
さてTDateTime型をEditに表示したりするときにはString型に変換する必要があります。
それには次の関数を利用します。
・TimeToStr関数、DateToStr関数、DateTimeToStr関数
TDateTime値を文字列に変換します。
それぞれの関数を使った場合と表示値の例を示します。
Edit1.Text := TimeToStr(Now); // 11:01:53
Edit2.Text := DateToStr(Now); // 2024/03/04
Edit3.Text := DateTimeToStr(Now); // 2024/03/04 11:01:53
上記のように区切り文字が時刻なら「:」、日付なら「/」となっているのは
ローカライゼーション情報(Windowsのコントロールパネルでの設定内容)を参照しているからです。
この設定が変わると表示値も変わります。
区切り文字だけではなく、年月日の並びや年の4桁表示、和暦表示も対象に含まれます。
逆にEditに入力した文字などをTDateTime型に変換するには次の関数があります。
・StrToTime関数、StrToDate関数、StrToDateTime関数
wDay := StrToDate(Edit1.Text);
このときEditに入力した文字の区切り文字がローカライゼーション情報のものと一致していないと
変換されず、エラーが発生しますのでご注意下さい。
このエラーを出さないようにチェックする関数が用意されています。
・TryStrToTime関数、TryStrToDate関数、TryStrToDateTime関数
入力した文字が日付時刻型に変換できるときには、Trueを返します。
次の例では、変換できるときにはwDayに変換後の値が入ります。
var
wDay : TDateTime;
begin
if TryStrToDate(Edit1.Text, wDay) = False then
begin
ShowMessage('日付が間違っています。');
end;
end;
・StrToDateDef関数、StrToTimeDef関数、StrToDateTimeDef関数
整数におけるStrToIntDefのように、変換に失敗した場合はエラーにするのではなく
引数で同時に指定するデフォルトの日付値や時刻値を返す関数もあります。
・FormatDateTime関数
日付や時刻を文字列に変換する際に使用します。これはTDateTime型を形式化します。
// 2024年03月04日
Edit10.Text := FormatDateTime('yyyy年mm月dd日',Now);
// 令和6年3月4日
Edit11.Text := FormatDateTime('gge年m月d日',Now);
FormatDateTimeのフォーマット設定で使用できる文字には以下のようなものがあります。
(以下例は『2024/03/04 05:06:07.890』をフォーマット設定した場合の結果文字列)
- <日付フォーマット>
- yまたはyy:24(西暦年下2桁)
- yyyまたはyyyy:2024(西暦年4桁)
- mまたはmmm:3(月)※
- mm:03(月の0埋め)※
- mmmm:3月(月の日本語表示)※
- d:4(日)
- dd:04(日の0埋め)
- dddまたはaaa:月(曜日ショート 日本語表示)※
- ddddまたはaaaa:月曜日(曜日ロング 日本語表示)※
- ddddd:2024/03/04(yyyy/mm/dd表記)
- dddddd:2024年3月4日(yyy年m月d日表記)
- g:令(元号の略称)
- gg:令和(元号)
- e:6(和暦)
- ee:06(和暦の0埋め)
- <時刻フォーマット>
- h:5(時)
- hh:05(時の0埋め)
- mまたはn:6(分)※
- mmまたはnn:06(分の0埋め)※
- s:7(秒)
- ss:07(秒の0埋め)
- zまたはzzz:890(ミリ秒)
- A/P:A(午前/午後 略称)※
- AMPM:AM(午前/午後)※
- AM/PM:AM(午前/午後)※
- t:5:06(hh:nn表記)
- tt:5:06:07(hh:nn:ss表記)
- <日付時刻フォーマット>
- c:2024/03/04 5:06:07(yyyy/mm/dd h:nn:ss表記)
- c:2024/03/04 5:06:07(yyyy/mm/dd h:nn:ss表記)
<その他の留意事項>(上記「※」部分)
- 大文字と小文字の区別はありませんが、同じ単語内では統一されている必要があります。
OK例「YY/m/d」「YYYY/MM/DD hh:nn:ss」、NG例「Yyyy」 - mmmm・ddd・ddddで「日本語表示」と記載した箇所は、厳密にはローカル言語での表示です。
英語環境の端末では「3月」「月」「月曜日」ではなく「March」「Mon」「Monday」と表示されます。 - m・mmは直前に「時」(h・hh)がある場合のみ「分」と見なされ、他は「月」と見なされます。
確実に「分」扱いしたい場合はnやnnを使用します。 - フォーマット文字列には「h時nn分ss秒」といった固定文字も設定できますが、
上記の予約文字を本当にその文字として表示させたい場合は””で囲みます。
(例「dd”hh:nn:ss”」⇒「04hh:nn:ss」と表示) - 午前/午後の文字列(AM/PM・A/P・AMPM)がフォーマット文字列に含まれる場合、
時(h・hh)は12時間表記になります。
・VarToDateTime関数
FormatDateTimeとは逆に、和暦で表された日付などをTDateTime型に変換します。
上記のFormatDateTimeでの規則に合致する文字列であれば、かなり柔軟に対応してくれます。
var
wDay1 : Variant;
wDay2 : TDateTime;
begin
wDay1 := '令和6年3月05日';
wDay2 := VarToDateTime(wDay1);
end;
日付時刻と数値の変換に用いる関数
日付型や時刻型を数値に保管したい場合、以下のような方法があります。
・TTimeStamp型の使用
TDateTime型はミリ秒まで表すことができますが、
時刻部分に演算誤差のない厳密な正確さが求められるときには、
TTimeStamp型を使って日付時刻値を表します。
時刻部分にミリ秒までの正確さが必要でない場合は、よりコンパクトなTDateTime型を使用します。
TTimeStampは内部的にはRecord型で、内部に「Date」「Time」という整数値を持っています。
以下のように「DateTimeToTimeStamp」関数を使用すると、
TDateTime型をTTimeStamp型の変数(下記例では「ts」)に変換できます。
TDateTime型に戻す場合は、これの逆で「TimeStampToDateTime」関数を使用します。
var
ts: TTimeStamp;
d: TDateTime;
begin
ts := DateTimeToTimeStamp(Now); // DateTime ⇒ TimeStamp
d := TimeStampToDateTime(ts); // TimeStamp ⇒ DateTime
end;
TTimeStampに変換した後の結果は以下のように保持されています。
例として記載しているのは「2024/03/04 05:06:07.890」を変換したときの結果です。
ts.Date:西暦1年1月1日からの累計日数(例:738949)
ts.Time:00時00分00秒からの累計ミリ秒(例:18367890)
・Encode・Decodeの使用
日付や時刻を年月日・時分秒に分解して保管したい場合やその逆を行いたい場合、
以下のような関数・手続きを利用可能です。
EncodeDate:年月日の各整数 ⇒ 日付型に変換
EncodeTime:時分秒+ミリ秒の各整数 ⇒ 時刻型に変換
DecodeDate:日付型 ⇒ 年月日の各整数に変換
DecodeTime:時刻型 ⇒ 時分秒+ミリ秒の各整数に変換
それぞれのロジック例は以下のようになります。
var
d, dd: TDateTime; // 結果セット用
iYY, iMM, iDD: Word; // 日付用 Integer型ではなくWord型を指定
iHH, iNN, iSS, iZZ: Word; // 時刻用 Integer型ではなくWord型を指定
begin
// 日付の変換処理
DecodeDate(Now, iYY, iMM, iDD); // 日付型⇒年月日の整数
d := EncodeDate(iYY, iMM, iDD); // 年月日の整数⇒日付型
// 日付の結果表示例
ShowMessage(iYY.ToString + #13#10 + iMM.ToString + #13#10 + iDD.ToString);
ShowMessage(FormatDateTime('YYYY/MM/DD', d));
// 時刻の変換処理
DecodeTime(Now, iHH, iNN, iSS, iZZ); // 時刻型⇒時分秒+ミリ秒の整数
dd := EncodeTime(iHH, iNN, iSS, iZZ); // 時分秒+ミリ秒の整数⇒時刻型
// 時刻の結果表示例
ShowMessage(iHH.ToString + #13#10 + iNN.ToString + #13#10 +
iSS.ToString + #13#10 + iZZ.ToString);
ShowMessage(FormatDateTime('HH:NN:SS.ZZZ', dd));
EncodeDateとEncodeTimeは、それぞれ存在しない日付や時刻を引数に渡すとエラーになります。
先述のTryStrToTime・TryStrToDate・TryStrToDateTimeと同様に、
こちらの関数にも日付や時刻の常識チェックを行うTryEncodeDate・TryEncodeTimeが存在します。
//(例)
if not(TryEncodeDate(2025, 2, 29, wDay)) then
begin
ShowMessage('日付が間違っています。');
end;
日付の計算に用いる関数
先述の通り、TDateTime型は整数部は西暦1899/12/30からの経過日数を示すので、
日付の計算も次のように簡単に行えます。
- 翌日 wDay + 1
- 昨日 wDay – 1
2024/03/31の翌日は2024/04/01となります。
また次のような関数も用意されています。
・IncYear関数
指定された年数で変更された日付を返します。
負の値を指定すると、N年前の日付を返すことができます。
- 翌年 IncYear(wDay, 1)
- 前年 IncYear(wDay, -1)
・IncMonth関数
指定された月数で変更された日付を返します。
負の値を指定すると、Nヶ月前の日付を返すことができます。
- 翌月 IncMonth(wDay, 1)
- 前月 IncMonth(wDay, -1)
このとき、2024/03/31の翌月「IncMonth(wDay, 1)」とすると、
2024/04/30となりますので、ご注意下さい。
・DaysBetween関数
uses節にDateUtilsを追加すると、
指定された2つのTDateTime値の間にある日数をInteger型で取得できます。
Daysbetween(wDay1,wDay2)とDaysbetween(wDay2,wDay1)は同じ値で、
以下の例では「7」になります。
wDay1 := StrToDate('2024/04/26');
wDay2 := StrToDate('2024/05/03');
Edit1.Text := IntToStr(Daysbetween(wDay1,wDay2));
DateUtilsユニットを追加したくない場合は、
小数部を切り捨てた値を引き算して絶対値を求めるといった代替手段も可能です。
wDay1 := StrToDate('2024/04/26');
wDay2 := StrToDate('2024/05/03');
Edit1.Text := IntToStr(Abs(Trunc(wDay1) - Trunc(wDay2)));
関連リンク
【株式会社ミガロ.30周年記念】Delphi/400 シンプル共通関数30選(MIGARO. 技術Tips)
今回ご紹介した関数を組み合わせて、以下の処理をシンプルに行う共通関数の作成方法をご紹介しています。
- 日付整数値(YYYYMMDD)とDelphi日付型の変換処理
- 時刻整数値(HHNNSS)とDelphi時刻型の変換処理
- 半年前(nヶ月前)の日付を取得する
- 当月末日の日付値を取得する処理
【Delphi】日付の標準フォーマット(MIGARO. 技術Tips)
FormatSettingsの文字列設定や変更について。
System.DateUtils – RAD Studio API Documentation
(DateUtilsユニットについてはこちら。本記事で紹介しきれなかった関数も多数記載されています。)
(ミガロ.情報マガジン「MIGARO News!!」Vol.57 2005年10月号より)
(ミガロ.情報マガジン「MIGARO News!!」Vol.58 2005年11月号より)
(ミガロ.情報マガジン「MIGARO News!!」Vol.59 2005年12月号より)
※年月はそれぞれ現在のものに変更