本日から指定の日付までの日数を計算する Windows デスクトップ・プログラム DaysUntil を紹介しています。
大きなイベントのある日まで、あと何日あるかを知りたかったので、計算してくれるアプリを作成しました。 同様のことを提供しているウェブサイトなどもありますが、現世代の開発者が直面しないであろう、 うるう年の例外処理をあわせて残しておく目的もあります。
Win7 + Visual C++ 2013 / MFC で、ダイアログアプリとして作成していますが、計算部分についてはOS等には依存しません。 使用している Windows API は、同等の関数に置き換えれば、計算部分はそのまま他のOSや言語でも利用可能と思いますので、 関数などを含めて、ここで紹介しています。
このページにトピック一覧がありますので、あわせてご参照ください。
ご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。
2018 年 12 月 4 日に更新があります。
2020 年 1 月 27 日更新のお知らせ
2020 年 11 月 4 日のお知らせ
投稿 February 22, 2018、更新 January 27, 2020
起動すると、次のような画面が表示されます。
起動時には、中央のコンボボックスには、本日の日付が設定され、 イメージの「あと 347日です」の部分には、「あと 0日です」と表示されます。
コンボボックスで、計算したい年月日を設定し、「計算する」ボタンを押すと、計算結果が表示されます。
このプログラムでは、本日よりあとの日付のみ対象としていますので、「あの日から今日まで何日経過したか」のような
過去からの、あるいは過去への日付は計算できません。
年、月をまたぐ計算や、うるう年の確認のため、テスト機能として、コンボボックスの日付を+1、−1日できるボタンを用意しています。 このボタンを押すと、「計算する」ボタンを押さなくても、自動的に画面が更新されるようにしています。
私なら、完全に信用できるサイト以外からのダウンロードはしませんが、
興味がある方のために、実行ファイルを圧縮したものを置いておきます。
安全に努めているマシンで用意したファイルですが、お試しいただく場合は、完全に自己責任でお願いします。
OSは Windows 7 以降、ランタイムなど環境の用意は
[2018/12/04]
「本日」が12月(起動日が12月)のとき、翌年以降の日数を計算すると、31日多く表示されていたことがわかりました。
起動日が11月より前のときは、問題はありません。
下記リンク先、タイムスタンプ、サイズは、修正版のものとなっています。
具体的には、calcDaysWithinTheYear 関数をご参照ください。
実行ファイルを含む zip ファイルのダウンロードは、
https://www.straightapps.com/download/daysuntil.zip
です。上記 URL をブラウザのアドレスバーに入力すると、ダウンロードできます。
正しい zip ファイルのタイムスタンプは 2018/12/4 14:05:02、
正しい実行ファイルのタイムスタンプ(更新日時)は 2018/12/4 14:02:32 で、
zip 内は実行ファイル1つだけです。
zip ファイルサイズは 175,572 バイト、
実行ファイルのサイズは 345,088 バイトです。
パスワードは設定していません。
投稿 February 22, 2018、更新 January 27, 2020(様式変更)
Windows API では、本日の日付の取得は簡単です。 画面表示のために、ダイアログの初期化 OnInitDialog 関数で、本日の日付を取得しています。
操作中に日付が変わることは考えず、「計算する」ボタンを押したときにも再取得していますので、 アプリ起動中に日付が変わると(起動しっぱなしとか)、画面上で不一致が発生します。 正式リリースするなら、日付が変わったら画面表示を更新するか、起動時に画面表示した日付を覚えておいてそれを使う、 のような工夫が必要です。
// 今日の日付を取得して、画面に表示します。 SYSTEMTIME st; GetLocalTime(&st); CString str; str.Format(_T("今日は %d年 %d月 %d日です。"), st.wYear, st.wMonth, st.wDay); SetDlgItemText(IDC_TODAY, str);
ここには関係ありませんが、Android ネイティブアプリで日付を取得する方法は、 「C/C++ による現在日時の取得」に書いています。
年については、ドロップダウン・コンボボックスとして、 とりあえず10年先までををリストに入れて、手入力も可能としています。
月については、ドロップダウンリスト・コンボボックスで、 1〜12を選べます。
日については、ドロップダウンリスト・コンボボックスですが、 月により日数が異なります。 また、2月の場合は、年によっても異なります。
ある年月の日数を返す関数を作成しました。
int getDaysOfMonth(int nYear, int nMonth) { // 2月は特別に扱います。 if (nMonth == 2){ if (isLeapYear(nYear)){ // うるう年であれば return 29; // 29日まであります。 } return 28; // そうでなければ、28日までです。 } // 次に、30日ある月であれば、30を返します。 if (nMonth == 4 || nMonth == 6 || nMonth == 9 || nMonth == 11){ return 30; } // それ以外は、31日まである月です。 return 31; }
isLeapYear 関数が、うるう年の判定をしています。
うるう年は 4 で割り切れる年ですが、100 でも割り切れる年はうるう年ではありません。ただし、400 で割り切れる年は、うるう年です。
bool isLeapYear(int nYear) { // 4で割り切れない年は、うるう年ではありません。 if (nYear % 4){ return false; } // 4で割り切れても、400でも割り切れるなら、うるう年です。 if (!(nYear % 400)){ return true; } // 4で割り切れ、400では割り切れないが、100で割り切れるなら、うるう年ではありません。 if (!(nYear % 100)){ return false; } // 4で割り切れ、100でも 400でも割れない年は、うるう年です。 return true; }
うるう年処理に関するマイクロソフトのエントリでは、1行に書いていました。
// うるう年かどうかチェック
bool leap = st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
ベテランの方は 2000 年問題 Y2K 問題に直面していますから気になりますが、 フレッシュな世代の方は 2100 年まで、例外処理しない実装でも困りません。 2100 年にまた騒がしくなるのでしょうか?
うるう年ではないですが、もっとベテランの方は 昭和から平成で困ったことがあったかも知れません。 逆に、フレッシュな世代の方は、平成から新元号・令和に変わったときに何かあったかも知れませんが、 行政系以外では西暦使用が一般的になりましたから、それほど問題でもないでしょうか。
投稿 February 22, 2018、更新 August 1, 2018(様式変更)
計算するのが同年同月内であれば、日付の差を計算するだけで終わりです。
今日の日付を nDayFrom、知りたい日付を nDayTo とすれば、
次のように書けます。
nDiff = nDayTo - nDayFrom;
同年で月が違うときは、今月の残りの日数に、挟まれている月の日数を足し、さらに最終月の指定の日数を足しています。
今日を nYearFrom、nMonthFrom、 nDayFrom、
知りたい日付を nYearTo、nMonthTo、nDayTo としています。
// 今月の残り日数を計算します。 // 31日ある月の 30日なら、今月の残り日数は 1 です。 nDiff = getDaysOfMonth(nYearFrom, nMonthFrom) - nDayFrom; // 挟まっている月の日数を加算します。 int nCurMonth = nMonthFrom + 1; // 翌月 while (nCurMonth < nMonthTo){ // 目標の月の前月まで nDiff += getDaysOfMonth(nYearFrom, nCurMonth); nCurMonth++; } // 目標の月の日数を加算します。 nDiff += nDayTo;
年も違うときは、今の年の年末までの日数に、
挟まれている年の日数を足し、目標の月の前月までの日数をプラス、最後に最終月の指定の日数を足しています。
今日を nYearFrom、nMonthFrom、nDayFrom、
知りたい日付を nYearTo、nMonthTo、nDayTo としています。
// 今年の12月31日までの残り日数を計算 nDiff = calcDaysWithinTheYear(nYearFrom, nMonthFrom, nDayFrom); // 挟まっている年の日数を加算します。 int nCurYear = nYearFrom + 1; // 翌年 while (nCurYear < nYearTo){ // 目標の年の前年まで nDiff += (isLeapYear(nCurYear) ? 366 : 365); nCurYear++; } // 挟まっている月の日数を加算します。 int nCurMonth = 1; // 1月から while (nCurMonth < nMonthTo){ // 目標の月の前月まで nDiff += getDaysOfMonth(nYearTo, nCurMonth); nCurMonth++; } // 目標の月の日数を加算します。 nDiff += nDayTo;
int calcDaysWithinTheYear(int nYear, int nMonthFrom, int nDayFrom) { int nDiff; int nMonthTo = 12; int nDayTo = 31; // 今月の残り日数を計算します。 // 31日ある月の 30日なら、今月の残り日数は 1 です。 nDiff = getDaysOfMonth(nYear, nMonthFrom) - nDayFrom; // 今月が12月の場合は、nDayTo をクリアしておく必要があります。 if (nMonthFrom == 12){ nDayTo = 0; } // 挟まっている月の日数を加算します。 int nCurMonth = nMonthFrom + 1; // 翌月 while (nCurMonth < nMonthTo){ // 目標の月の前月まで nDiff += getDaysOfMonth(nYear, nCurMonth); nCurMonth++; } // 目標の月の日数を加算します。 nDiff += nDayTo; return nDiff; }
[2018/12/4] nDayTo を0クリアしている部分が追加されています。
元の流れとしては、
1)今月の月末までの日数を計算(端数になる日数)。
2)それに、目的の月の前の月までの日数を加算(まるまる含まれる月の部分)。
3)それに、12月の日数(31)を加算。
となっていました。
本日が12月の場合、12月の残りの日数をはじめに設定し、さらに最後に31を足してしまっているため、正しく計算されていませんでした。
12月の場合の例外処理を入れましたが、本来的には上記2の計算で、12月までを入れるべきとも考えられます。
投稿 February 22, 2018、更新 August 1, 2018(様式変更)
すっかり忘れてしまっていたので、自分用のメモを兼ねて、プログラムから既定のブラウザでウェブページを開くコードを書いておきます。
このユーティリティでは、画面右下の日付とサイト名の部分をクリックすると、このサイトが開くようになっています。
スタティック・コントロールにIDを付けて、
Notify プロパティを True に変更、
Click のハンドラから、ShellExecute 関数を呼び出します。
msdn での説明は こちら。
マウスポインタの形状は矢印のままなので、隠し機能みたいになっています。
本当は、わかりやすくすべきです。
ShellExecute(GetSafeHwnd(), _T("open"), _T("https://www.straightapps.com/win/"), NULL, NULL, SW_SHOWNORMAL);呼び出し元がダイアログのクリック処理のため、CWnd のウィンドウハンドル HWND を得る、GetSafeHwnd 関数を使っています。 また、文字の形式を自動で統一するため、_Tを使っています。
関連トピックはありません。
おすすめ記事はありません。