このサイトでは、分析、カスタマイズされたコンテンツ、および広告に Cookie を使用します。このサイトを引き続き閲覧すると、Cookie の使用に同意するものと見なされます。
Hi, Developers,
straightapps.com
投稿 February 22, 2018、最終更新 April 26, 2019(様式変更)
トップページ > Windows トップ > DaysUntil

Windows 開発

DaysUntil は、指定の日まであと何日かを計算するユーティリティです。

本日から指定の日付までの日数を計算する Windows デスクトップ・プログラム DaysUntil を紹介しています。

大きなイベントのある日まで、あと何日あるかを知りたかったので、計算してくれるアプリを作成しました。 同様のことを提供しているウェブサイトなどもありますが、現世代の開発者が直面しないであろう、 うるう年の例外処理をあわせて残しておく目的もあります。

Win7 + Visual C++ 2013/MFC で、ダイアログアプリとして作成していますが、計算部分についてはOS等には依存しません。 使用している Windows API は、同等の関数に置き換えれば、計算部分はそのまま他のOSや言語でも利用可能と思いますので、 関数などを含めて、ここで紹介しています。

このページにトピック一覧がありますので、あわせてご参照ください。
ご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。

- 更新があります -
[2018/12/4] 「本日」が12月のとき、年をまたぐ日数を計算すると31日多く表示される不具合がありました。 修正版があります。

どんな動作をするのか

投稿 February 22, 2018、更新 August 1, 2018(様式変更)

起動すると、次のような画面が表示されます。

起動時には、中央のコンボボックスには、本日の日付が設定され、 イメージの「あと 347日です」の部分には、「あと 0日です」と表示されます。

コンボボックスで、計算したい年月日を設定し、「計算する」ボタンを押すと、計算結果が表示されます。
このプログラムでは、本日よりあとの日付のみ対象としていますので、「あの日から今日まで何日経過したか」のような 過去からの、あるいは過去への日付は計算できません。

年、月をまたぐ計算や、うるう年の確認のため、テスト機能として、コンボボックスの日付を+1、−1日できるボタンを用意しています。 このボタンを押すと、「計算する」ボタンを押さなくても、自動的に画面が更新されるようにしています。

私なら、完全に信用できるサイト以外からのダウンロードはしませんが、 興味がある方のために、実行ファイルを圧縮したものを置いておきます。 安全に努めているマシンで用意したファイルですが、お試しいただく場合は、完全に自己責任でお願いします。
OSは Windows 7 以降、ランタイムなど環境の用意は 特に必要ない ( MFC ライブラリはスタティックリンクしています。 ) と思います。

[2018/12/04]
「本日」が12月(起動日が12月)のとき、翌年以降の日数を計算すると、31日多く表示されていたことがわかりました。 起動日が11月より前のときは、問題はありません。
下記リンク先、タイムスタンプ、サイズは、修正版のものとなっています。
具体的には、
calcDaysWithinTheYear 関数をご参照ください。

実行ファイルを含む zip ファイルのダウンロードは、こちらです。
正しい zip ファイルのタイムスタンプは 2018/12/4 14:05:02、 正しい実行ファイルのタイムスタンプ(更新日時)は 2018/12/4 14:02:32 で、 zip 内は実行ファイル1つだけです。 zip ファイルサイズは 175,572 バイト、 実行ファイルのサイズは 345,088 バイトです。 パスワードは設定していません。

▲ページ先頭へ

本日の日付の取得

投稿 February 22, 2018、更新 August 1, 2018(様式変更)

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 ネイティブアプリで日付を取得する方法は、 こちらに書いています。ご参考まで。

年については、ドロップダウン・コンボボックスとして、とりあえず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;

同年で月が違うときは、今月の残りの日数に、挟まれている月の日数を足し、さらに最終月の指定の日数を足しています。
今日を nYearFromnMonthFromnDayFrom、 知りたい日付を nYearTonMonthTonDayTo としています。

// 今月の残り日数を計算します。
// 31日ある月の 30日なら、今月の残り日数は 1 です。
nDiff = getDaysOfMonth(nYearFrom, nMonthFrom) - nDayFrom;

// 挟まっている月の日数を加算します。
int nCurMonth = nMonthFrom + 1; // 翌月
while (nCurMonth < nMonthTo){ // 目標の月の前月まで
	nDiff += getDaysOfMonth(nYearFrom, nCurMonth);
	nCurMonth++;
}

// 目標の月の日数を加算します。
nDiff += nDayTo;

年も違うときは、今の年の年末までの日数に、 挟まれている年の日数を足し、目標の月の前月までの日数をプラス、最後に最終月の指定の日数を足しています。
今日を nYearFromnMonthFromnDayFrom、 知りたい日付を nYearTonMonthTonDayTo としています。

// 今年の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を使っています。

▲ページ先頭へ


関連トピックス

関連トピックはありません。


その他のおすすめ

おすすめ記事はありません。



© 2017-2019 StraightApps.com 無断転載を禁じます。No reproduction without permission.