C > datetime > 次のインターバルの日時を取得する > 3種類 

関連 http://qiita.com/7of9/items/de6c27373f8fe3e9cd92
関連 http://qiita.com/7of9/items/42a5a25afdd485d28fb2

## 仕様

- 開始日時: yyyy/mm/dd hh:nn
- インターバル(hour): 例 6
- 現在時刻: yyyy/mm/dd hh:nn

上記の設定値から次のインターバルとなる日時を取得する。

Cで実装すること。


## 方法1 (nowから秒を増やしていく作戦)

安易な方法として、現在時刻から秒数を加算していき、[開始日時 + N*インターバル]の日時になった時点でループを抜ける。


### code

<font color=red>
(追記 2016/03/31)
workdt.tm_mon = mm;は間違いのようです。
workdt.tm_mon = mm - 1; // 月（ 1月＝0 ）
</font>


http://ideone.com/uD04iM

loopはideoneに迷惑をかけないための上限設定に使用。

```.c
#include <stdio.h>
#include <time.h> // 試験用の秒を得るために使用. 開発環境には存在しない

time_t getElapsedSecond(int yyyy, int mm, int dd, int hh, int nn){
	struct tm workdt;
	workdt.tm_isdst = -1; // summer time flag
	workdt.tm_year = yyyy - 1900;
	workdt.tm_mon = mm;
	workdt.tm_mday = dd;
	workdt.tm_hour = hh;
	workdt.tm_min = nn;
	workdt.tm_sec = 0;
	return mktime(&workdt);
}

void getDateTimeString(time_t srcdt, char *dstPtr)
{
	if (dstPtr == NULL) {
		return; // error
	}
	struct tm *workdt;
	workdt = localtime(&srcdt);	
	workdt->tm_year = workdt->tm_year + 1900;
	sprintf(dstPtr, "%04d/%02d/%02d %02d:%02d", workdt->tm_year, workdt->tm_mon, workdt->tm_mday, 
		workdt->tm_hour, workdt->tm_min);
}

//----- こちらから上は開発環境にない関数を使用する。2つの日時の秒数を取得するためだけに使用
//
//----- こちらから下に試験を行う関数を実装

void printNextDateTime_loop(time_t start_sec, time_t now_sec, int itvl_hr)
{
	char szBuf[100];
	time_t work_sec;
	time_t loop;
	time_t itvl_sec = itvl_hr * 60 * 60;

	work_sec = now_sec;

//	printf("%u\n", work_sec);
//	printf("%u\n", start_sec + itvl_sec);

	loop = 0;
	while(loop < 100000) {
		if ((work_sec - start_sec) % itvl_sec == 0) {
			break;
		}
		work_sec++;
		loop++;
	}

	printf("interval(hour)=%d\n", itvl_hr);
	getDateTimeString(start_sec, szBuf);
	printf("start:%s\n", szBuf);
	getDateTimeString(work_sec, szBuf);
	printf("next :%s\n", szBuf);
}

int main(void) {
	time_t start_sec;
	time_t now_sec;
	int itvl_hr = 6; // interval in hour
	
	start_sec = getElapsedSecond(2016, 3, 27, 18, 30);
	now_sec = getElapsedSecond(2016, 3, 28, 5, 12);
	
	printNextDateTime_loop(start_sec, now_sec, itvl_hr);
	
	return 0;
}
```

```txt:結果
Success	time: 0 memory: 2288 signal:0
interval(hour)=6
start:2016/03/27 18:30
next :2016/03/28 06:30
```

## 方法2 (startからインターバル秒増やしていく作戦)

### code

<font color=red>
(追記 2016/03/31)
workdt.tm_mon = mm;は間違いのようです。
workdt.tm_mon = mm - 1; // 月（ 1月＝0 ）
</font>

http://ideone.com/ahswrm

printNextDateTime_intervalStepLoop()を実装。

```.c
#include <stdio.h>
#include <time.h> // 試験用の秒を得るために使用. 開発環境には存在しない

time_t getElapsedSecond(int yyyy, int mm, int dd, int hh, int nn){
	struct tm workdt;
	workdt.tm_isdst = -1; // summer time flag
	workdt.tm_year = yyyy - 1900;
	workdt.tm_mon = mm;
	workdt.tm_mday = dd;
	workdt.tm_hour = hh;
	workdt.tm_min = nn;
	workdt.tm_sec = 0;
	return mktime(&workdt);
}

void getDateTimeString(time_t srcdt, char *dstPtr)
{
	if (dstPtr == NULL) {
		return; // error
	}
	struct tm *workdt;
	workdt = localtime(&srcdt);	
	workdt->tm_year = workdt->tm_year + 1900;
	sprintf(dstPtr, "%04d/%02d/%02d %02d:%02d", workdt->tm_year, workdt->tm_mon, workdt->tm_mday, 
		workdt->tm_hour, workdt->tm_min);
}

//----- こちらから上は開発環境にない関数を使用する。2つの日時の秒数を取得するためだけに使用
//
//----- こちらから下に試験を行う関数を実装

void printNextDateTime_loop(time_t start_sec, time_t now_sec, int itvl_hr)
{
	char szBuf[100];
	time_t work_sec;
	time_t loop;
	time_t itvl_sec = itvl_hr * 60 * 60;

	work_sec = now_sec;

//	printf("%u\n", work_sec);
//	printf("%u\n", start_sec + itvl_sec);

	loop = 0;
	while(loop < 100000) {
		if ((work_sec - start_sec) % itvl_sec == 0) {
			break;
		}
		work_sec++;
		loop++;
	}

	printf("interval(hour)=%d\n", itvl_hr);
	getDateTimeString(start_sec, szBuf);
	printf("start:%s\n", szBuf);
	getDateTimeString(work_sec, szBuf);
	printf("next :%s\n", szBuf);
}

void printNextDateTime_intervalStepLoop(time_t start_sec, time_t now_sec, int itvl_hr)
{
	char szBuf[100];
	time_t work_sec;
	time_t loop;
	time_t itvl_sec = itvl_hr * 60 * 60;

	work_sec = now_sec;

//	printf("%u\n", work_sec);
//	printf("%u\n", start_sec + itvl_sec);

	loop = 0;
	work_sec = start_sec;
	while(loop < 100) {
		if (work_sec >= now_sec) {
			break;
		}
		work_sec += itvl_sec;
		loop++;
	}

	printf("interval(hour)=%d\n", itvl_hr);
	getDateTimeString(start_sec, szBuf);
	printf("start:%s\n", szBuf);
	getDateTimeString(work_sec, szBuf);
	printf("next :%s\n", szBuf);
}


int main(void) {
	time_t start_sec;
	time_t now_sec;
	int itvl_hr = 6; // interval in hour
	
	start_sec = getElapsedSecond(2016, 3, 27, 18, 30);
	now_sec = getElapsedSecond(2016, 3, 28, 0, 30);
	
	printNextDateTime_loop(start_sec, now_sec, itvl_hr);
	printNextDateTime_intervalStepLoop(start_sec, now_sec, itvl_hr);
	
	return 0;
}
```

```txt:結果
Success	time: 0 memory: 2288 signal:0
interval(hour)=6
start:2016/03/27 18:30
next :2016/03/28 00:30
interval(hour)=6
start:2016/03/27 18:30
next :2016/03/28 00:30
```

nowが`start + N*インターバル`丁度での結果。丁度でない場合も確認した。

## 方法3 (N倍を計算する)

### 方法

![](http://yuml.me/diagram/class/[Start]-->[1 x itvl], [1 x itvl]-Now->[Next(2 x itvl)])

あるいは

![](http://yuml.me/diagram/class/[Start]-->[1 x itvl], [1 x itvl]-->[Now|Next(2 x itvl)])


以下を計算する。
int型での割り算は小さい方の数値になる（はず）なので、上記の2ケースに対応する（はず）。

```
ntimes = (int)(now_sec - start_sec) / itvl_sec;
work_sec = start_sec + ntimes * itvl_sec;
```


### code

<font color=red>
(追記 2016/03/31)
workdt.tm_mon = mm;は間違いのようです。
workdt.tm_mon = mm - 1; // 月（ 1月＝0 ）
</font>

http://ideone.com/mcod6d

printNextDateTime_calcNtimes()として実装

```.c
#include <stdio.h>
#include <time.h> // 試験用の秒を得るために使用. 開発環境には存在しない

time_t getElapsedSecond(int yyyy, int mm, int dd, int hh, int nn){
	struct tm workdt;
	workdt.tm_isdst = -1; // summer time flag
	workdt.tm_year = yyyy - 1900;
	workdt.tm_mon = mm;
	workdt.tm_mday = dd;
	workdt.tm_hour = hh;
	workdt.tm_min = nn;
	workdt.tm_sec = 0;
	return mktime(&workdt);
}

void getDateTimeString(time_t srcdt, char *dstPtr)
{
	if (dstPtr == NULL) {
		return; // error
	}
	struct tm *workdt;
	workdt = localtime(&srcdt);	
	workdt->tm_year = workdt->tm_year + 1900;
	sprintf(dstPtr, "%04d/%02d/%02d %02d:%02d", workdt->tm_year, workdt->tm_mon, workdt->tm_mday, 
		workdt->tm_hour, workdt->tm_min);
}

//----- こちらから上は開発環境にない関数を使用する。2つの日時の秒数を取得するためだけに使用
//
//----- こちらから下に試験を行う関数を実装

void printNextDateTime_loop(time_t start_sec, time_t now_sec, int itvl_hr)
{
	char szBuf[100];
	time_t work_sec;
	time_t loop;
	time_t itvl_sec = itvl_hr * 60 * 60;

	work_sec = now_sec;

//	printf("%u\n", work_sec);
//	printf("%u\n", start_sec + itvl_sec);

	loop = 0;
	while(loop < 100000) {
		if ((work_sec - start_sec) % itvl_sec == 0) {
			break;
		}
		work_sec++;
		loop++;
	}

	printf("interval(hour)=%d\n", itvl_hr);
	getDateTimeString(start_sec, szBuf);
	printf("start:%s\n", szBuf);
	getDateTimeString(work_sec, szBuf);
	printf("next :%s\n", szBuf);
}

void printNextDateTime_intervalStepLoop(time_t start_sec, time_t now_sec, int itvl_hr)
{
	char szBuf[100];
	time_t work_sec;
	time_t loop;
	time_t itvl_sec = itvl_hr * 60 * 60;

	work_sec = now_sec;

//	printf("%u\n", work_sec);
//	printf("%u\n", start_sec + itvl_sec);

	loop = 0;
	work_sec = start_sec;
	while(loop < 100) {
		if (work_sec >= now_sec) {
			break;
		}
		work_sec += itvl_sec;
		loop++;
	}

	printf("interval(hour)=%d\n", itvl_hr);
	getDateTimeString(start_sec, szBuf);
	printf("start:%s\n", szBuf);
	getDateTimeString(work_sec, szBuf);
	printf("next :%s\n", szBuf);
}

void printNextDateTime_calcNtimes(time_t start_sec, time_t now_sec, int itvl_hr)
{
	char szBuf[100];
	time_t work_sec;
	time_t loop;
	time_t itvl_sec = itvl_hr * 60 * 60;
	int ntimes;

	work_sec = now_sec;
	
	ntimes = (int)(now_sec - start_sec) / itvl_sec;
	work_sec = start_sec + ntimes * itvl_sec;

// //	printf("%u\n", work_sec);
// //	printf("%u\n", start_sec + itvl_sec);

	printf("interval(hour)=%d\n", itvl_hr);
	getDateTimeString(start_sec, szBuf);
	printf("start:%s\n", szBuf);
	getDateTimeString(work_sec, szBuf);
	printf("next :%s\n", szBuf);
}



int main(void) {
	time_t start_sec;
	time_t now_sec;
	int itvl_hr = 6; // interval in hour
	
	start_sec = getElapsedSecond(2016, 3, 27, 18, 30);
	now_sec = getElapsedSecond(2016, 3, 28, 0, 30);
	
	printNextDateTime_loop(start_sec, now_sec, itvl_hr);
	printNextDateTime_calcNtimes(start_sec, now_sec, itvl_hr);
	
	return 0;
}
```

```txt:結果
Success	time: 0 memory: 2244 signal:0
interval(hour)=6
start:2016/03/27 18:30
next :2016/03/28 00:30
interval(hour)=6
start:2016/03/27 18:30
next :2016/03/28 00:30
```


## NowとNextの重なり

NowとNextが重なったときにNextを`Now + itvl_sec`とするかどうかは別途、要検討。