概要

 ファイル・フォルダーの日時を変更するサンプルプログラムを作成しました。
 このプログラムは更新日はそのままで時刻を0時0分0秒の日時を作成し、ファイルの作成日時,更新日時,アクセス日時を変更します。
 以下に実行例を示します。
        
D:\flower\IMG_2422.JPG
        2018/11/26 20:01:56     2018/11/26 20:01:56     2018/05/25 13:18:40
Chg     2018/05/25 00:00:00
Returnキーを押すと終了します。
 上の実行例は、1行目がファイル名、2行目が左から変更前の作成日時・アクセス日時・更新日時、3行目が変更後の日時です。
 コマンドラインベースのプログラムですが、プログラムファイル(mtouch2.exe)又はプログラムファイルのショートカットに変更したいファイル・フォルダーをドラックすれば変更できます。
 また複数ファイルにも対応しています。

テスト環境

コンパイラ

Visual C++ 2008/2013 Express 32bit/64bit マルチバイト/UNICODE

実行環境

Windows 10 Home Version 1803 64bit

プログラムソースの概要

_tmain

 Windowsから最初に呼び出される関数です。
 日本語が正しく表示できるように_tsetlocal関数を呼び出します。
 コマンドライン引数のファイル名がダブルコーテーションで括られている時は削除します。
 _putts関数でファイル名を表示します。
 file_time_touch関数でファイルの時刻を0時0分0秒に変更します。

file_time_touch

 日時を修正するためにCreateFile APIでファイル・フォルダーのハンドルを取得する必要があります。
 フォルダーのハンドルを取得する場合、CreateFile APIの第6引数にFILE_FLAG_BACKUP_SEMANTICSを指定しないとエラーが発生します。
 まず、GetFileAttribute APIで属性を取得します。
 属性がディレクトリ(FILE_ATTRBUTE_DIRECTORY属性が有効)の場合はCreateFile APIの第6引数にFILE_FLAG_BACKUP_SEMANTICSを、ファイルの場合はFILE_ATTRIBUTE_NOMALを設定します。

ファイル・フォルダーの日時を取得する。

 GetFileTime APIでファイルの作成日時・アクセス日時・更新日時を取得します。
 GetFileTime APIで取得できる日時はファイルタイムと呼ばれるもので1601年(関ヶ原の戦いの年)1月1日から100n秒(0.1μ秒=10-7秒)で表される64bitの整数です。
 まず取得された日時は協定世界時(UTC)ですのでFileTimeToLocalFileTime APIで日本時刻(64bit整数)に変換します。(9時間を加算)
 FileTimeToSystemTime APIによりローカルタイム{日本時刻(64bit整数)}を年月日・時分秒が分解されて扱いやすいSYSTEMTIME構造体に変換します。
 以下にminwinbase.hで定義されているSYSTEMTIME構造体を示します。
typedef struct _SYSTEMTIME {
    WORD wYear;         // 西暦
    WORD wMonth;        // 月
    WORD wDayOfWeek     // 曜日 日曜=0 土曜=6
    WORD wDay;          // 日
    WORD wHour;         // 時
    WORD wMinute;       // 分
    WORD wSecond;       // 秒
    WORD wMilliseconds; // ミリ秒
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
 SYSTEMTIME構造体では年月日や時分秒がメンバーとなっていますので_tprintf関数で作成日時・アクセス日時・更新日時を標準出力に表示します。

ファイル・フォルダーの日時を変更する。

 SYSTEMTIME構造体の時分秒のメンバーを0に代入します。
 日時の取得と逆の順番で日時を変換します。
 SYSTEMTIME構造体をSystemTimeToFileTime APIでファイルタイム{ローカルタイム 64bit整数}に変換します。
 ローカルタイムをLocalFileTimeToFileTime APIでUTCのファイルタイムに変換します。
 SYSTEMTIME構造体では年月日や時分秒がメンバーとなっていますので変更結果を_tprintf関数で標準出力に表示します。
 SetFileTime APIでファイル・フォルダーの日時を変更します。
 CloseHandle APIでファイル・フォルダーを閉じます。

ソースコード

// 指定されたファイル・フォルダーの時刻を00:00:00に変更する。
// Visual C++ 2008/2013 コマンドライン用

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <time.h>
#include <locale.h>

int file_time_touch(TCHAR* file_name);	// 指定されたファイル時刻を変更する

int _tmain(int argc, TCHAR** argv){
	_tsetlocale(LC_ALL, _TEXT(""));	//	UNICODE文字を標準出力に正しく表示できるように
	TCHAR* pass;
	if (argc == 1){
		_putts(_TEXT("使い方\nmtouch2 ファイル名またはフォルダー名"));

		return 1;
	}
	for (int n = 1; n < argc; n++){
		pass = argv[n];
		if (pass[0] == _T('\"')){
			size_t len = _tcslen(pass);
			if (pass[len - 1] == _T('\"'))
				pass[len - 1] = _T('\0');
			++pass;
		}
		_putts(pass);
		file_time_touch(pass);
	}
	_putts(_TEXT("Returnキーを押すと終了します。"));
	getchar();
	return 0;
}

// 指定されたファイルの日付を変更する

int file_time_touch(TCHAR* file_name){
	HANDLE hFile;
	DWORD attr = GetFileAttributes(file_name);
	hFile = CreateFile(file_name, GENERIC_WRITE, 0, 0, OPEN_ALWAYS,
		(attr & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE){
		_putts(_TEXT("File Open Error"));
		return -1;
	}
	FILETIME CreationTime;
	FILETIME AccessTime;
	FILETIME WriteTime;
	FILETIME localTime;
	FILETIME WriteTime2;
	SYSTEMTIME systemTime;

//	現在のファイルの日時を取得表示
	GetFileTime(hFile,&CreationTime,&AccessTime,&WriteTime);

	FileTimeToLocalFileTime(&CreationTime,&localTime);	//	UTC→ローカルタイム
	FileTimeToSystemTime(&localTime,&systemTime);	//	FILETIMEをSYSTEMTIMEに変換
	_tprintf(_TEXT("\t%i/%0.2i/%0.2i %0.2i:%0.2i:%0.2i"),systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute,systemTime.wSecond);

	FileTimeToLocalFileTime(&AccessTime,&localTime);	//	UTC→ローカルタイム
	FileTimeToSystemTime(&localTime,&systemTime);	//	FILETIMEをSYSTEMTIMEに変換
	_tprintf(_TEXT("\t%i/%0.2i/%0.2i %0.2i:%0.2i:%0.2i"),systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute,systemTime.wSecond);

	FileTimeToLocalFileTime(&WriteTime, &localTime);	//	UTC→ローカルタイム
	FileTimeToSystemTime(&localTime, &systemTime);	//	FILETIMEをSYSTEMTIMEに変換
	_tprintf(_TEXT("\t%i/%0.2i/%0.2i %0.2i:%0.2i:%0.2i\n"), systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
//	時刻のみ00:00:00にする
	systemTime.wHour = 0;
	systemTime.wMinute = 0;
	systemTime.wSecond = 0;
//	ファイルの日時の変更
	SystemTimeToFileTime(&systemTime, &localTime);	//	SYSTEMTIMEをFILETIMEに変換
	LocalFileTimeToFileTime(&localTime, &WriteTime2);	//	ローカルタイム→UTC

	_tprintf(_TEXT("Chg\t%i/%0.2i/%0.2i %0.2i:%0.2i:%0.2i\n"), systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond);


	if(SetFileTime(hFile,&WriteTime2,&WriteTime2,&WriteTime2)==0){
		_putts(_TEXT("\tSetFileTime API error"));
		CloseHandle(hFile);
		return -2;
	}
	CloseHandle(hFile);
	return 0;
}

実行ファイルとソースファイルのダウンロード