ここから本文です

指定した日付に、日数を加算し、その日付を求めたい

eighterxeighterさん

2012/8/2216:38:55

指定した日付に、日数を加算し、その日付を求めたい

指定した日付(A)に、日数(B)を加算し、その日付(C)を求めるような関数を作りたいです。
(A,B がIN で、 C がOUTです。)

検索すると、
指定した日付を、グレゴリウス暦1年1月1日を基準に、何日経過したか?
を求める方法などがあり、その日付(A')は求めることができました。

なので、
指定した日付(A) から、経過日数(A')を求め、
その日数に、(B)を加算し、再度日数から、日付(C)に戻そうと思ったのですが、
戻し方がわからなかったです。。。

いろんなページを見てみたのですが、
日付から日数はあるのですが、
日数から日付が見当たらなく困っています。

方法、もしくは参考になるページを教えていただければと思います。

よろしくお願いします。

閲覧数:
3,787
回答数:
3
お礼:
100枚

違反報告

ベストアンサーに選ばれた回答

lehshellさん

2012/8/2221:24:12

以下の文章内の行頭の `` は TAB に変換してください。

この手の問題で最も重要なのは
//--- date.h ----//
typedef struct {
``int year; // 西暦
``int month; // 月
``int day; // 日
} DATE;

/*
* OldDate 日付を Days 日数進め NewDate を求める
* Days < 0 の場合は日付は過去に戻る
*/
bool ForwardDate(const DATE *pOldDate, DATE *pNewDate, int nDays);
//--------------//
のようなヘッダファイルとこのインターフェースを実現する実装ファイル
date.c を作成し「経過日数」は date.c 内に隠蔽することだね。

> 指定した日付(A) から、経過日数(A')を求め、
> その日数に、(B)を加算し、再度日数から、日付(C)に戻そうと思ったのですが、
> 戻し方がわからなかったです。。。

1つの考え方としては...「日数」→「日付」として
1.「求める年」の前年の年末までの総日数を求める。
「日数」を 365 で割ることで「求める年」以上の年を一旦
求め1年ずつ小さくしていくことで「求める年」の前年を特定する。
2.「日数」から「総日数」を引いた「残りの日数」が「求める年」の1月1日からの
日数になるため、各月の日数の合計と比較しながら求める月を特定する。
3.「求める年」の1月1日から求める月の月末までの日数から求める月の日数を
引き、「求める年」の1月1日から求める月の「前月までの日数」を求める。
4.2項の「残りの日数」から「前月までの日数」を引き「求める日」を特定する。

static bool DaysToDate(int nDays, DATE *pDate)
{
``int year = nDays / 365;
``int tmpdays, subdays;
``int ni;
``bool bret = false;
``if (pDate) {
````// 該当年の前年を求める
````do {
``````tmpdays = (year * 365) + (year / 4) - (year / 100) + (year / 400);
````} while (tmpdays >= nDays ? --year : 0);
````pDate->year = ++year;
````// 該当年における1月1日からの日数を求める
````subdays = nDays - tmpdays;
````// 該当年における当月を求める
````tmpdays = 0;
````for (ni = 0; (tmpdays <= subdays) && (ni < 12); ++ni) {
``````tmpdays += DaysOfMonth(year, ni + 1);
````}
````pDate->month = ni;
````pDate->day = subdays - (tmpdays - DaysOfMonth(year, ni));
````bret = true;
``}
``return bret;
}

/*
* IN : year 西暦年,month 月(1~12) [year: 1 origin, month: 1 origin]
* OUT: 該当年の指定月の日数
*/
static int DaysOfMonth(int year, int month)
{
``static const char monlen[][13] = {
````{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
````{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
``};
``return monlen[IsLeap(year) ? 1 : 0][month];
}

/*
* if leap year then return true.
*/
static bool IsLeap(int year)
{
``return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
}

質問した人からのコメント

2012/8/24 12:34:59

降参 みなさん。ありがとうございます。
アホなりに、やっと理解しました。返事遅くなってすみません。
いろいろと勉強になりました。

「グレゴリウス暦」の検索結果

検索結果をもっと見る

ベストアンサー以外の回答

1〜2件/2件中

並び替え:回答日時の
新しい順
|古い順

2012/8/2405:54:16

/*

オーソドックスにグレゴリオ(グレゴリウス)暦を使うことにしました。
経過日数が数百万の場合も計算できます。もっともグレゴリオ暦はそんな遠い未来には適用できないという問題はありますが。
それから、経過日数が負で過去にさかのぼる処理は場合分けが面倒なので対応しておりません。

*/

#include <stdio.h>


typedef struct {
int year; // 年
int month; // 月
int day; // 日
} DATE;


int isleap_year(int year) // 閏年なら1を、平年なら0を返す関数
{
return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
}


void get_newdate(int days, const DATE *s, DATE *o)
{
int i;
int year, month, day, tmp_days, p_days, p_years, leap_y;


int m[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}};

year = s->year; // ポインタの記述が面倒なので変数を使うことにした
month = s->month;
day = s->day;
p_days = days;

tmp_days = p_years = 0;
if(p_days >= 365){
if(p_days == 365 && month == 1 && day == 1)
p_years = 0;
else {
p_years = (double)(p_days+isleap_year(year))/365.24219; // 経過年

for(i=year+1 ; i<year+p_years; i++) // 基準年の翌年から該当年の前年までの日数計算
tmp_days += 365 + isleap_year(i); // 閏年なら +1 される
//printf("前年末までの日数: %d\n", tmp_days);
leap_y=isleap_year(year); // 基準年が閏年かどうかの設定
for(i=month+1; i<= 12; i++) // 基準年の翌月から年末までの累計日数計算
tmp_days += m[leap_y][i];
//printf("翌月から年末までの日数: %d\n", tmp_days);
tmp_days += m[leap_y][month] - day; // 基準月の月末までの日数加算
//printf("月末までの日数: %d\n", tmp_days);
if(tmp_days == 0) p_years++;
}
}
year += p_years; // 基準年に経過年を加える

if(tmp_days == 0) {// 基準年内に収まる可能性があるとき
leap_y = isleap_year(year);
day += p_days;
for(i=month; (i<=12) && (day > m[leap_y][i]); i++)
day -= m[leap_y][i];
if(i<=12){
month = i;
o->year = year;
o->month = month;
o->day = day;
return;
}
else year++; // 翌年に持ち越し
}
else day = p_days - tmp_days; // 翌年以降が明らかなとき

leap_y = isleap_year(year);
i=1;
while(day > m[leap_y][i]){
day -= m[leap_y][i++];
if(i>12) i=1, leap_y=isleap_year(++year);
}
month=i;
o->year = year;
o->month = month;
o->day = day;
return;
}


int main(void)
{
int i;
int p_days;
DATE std_date, obj_date;

puts("基準となる日付(1582年10月15日以降)と経過日数から該当の日付を出力します");
do {
printf("基準年月日をスペースで区切って入力してください:");
scanf("%d%d%d",&std_date.year, &std_date.month, &std_date.day);
}while (std_date.year<1582); // 月日のデータチェックは省略
do {
printf("その日からの経過日数を入力してください:"); scanf("%d", &p_days);
} while(p_days < 0);
printf("基準年月日: %2d %2d %2d\n", std_date.year, std_date.month, std_date.day);
get_newdate(p_days, &std_date, &obj_date);
printf("該当年月日: %2d %2d %2d\n", obj_date.year, obj_date.month, obj_date.day);

return 0;
}

/*
■実行例1

基準となる日付(1582年10月15日以降)と経過日数から該当の日付を出力します
基準年月日をスペースで区切って入力してください:365 2 16
基準年月日をスペースで区切って入力してください:2012 1 5
その日からの経過日数を入力してください:365
基準年月日: 2012 1 5
該当年月日: 2013 1 4

■実行例2

基準年月日をスペースで区切って入力してください:1942 3 19
その日からの経過日数を入力してください:30000
基準年月日: 1942 3 19
該当年月日: 2024 5 7

*/

ajjfllさん

2012/8/2300:19:52

学校の課題としてグレゴリウス歴を使う場合は別ですが、time関数群に任せた方が楽なのでは・・・
出力は手抜きでctimeを使ってます。
漢字表示にしたい場合は、「localtime関数群」を活用して下さい。

動作確認は、LSIC .3.30C試食版でおこないました。

#include <stdio.h>
#include <time.h>

int main(void)
{
time_t tt;
struct tm tx;

tx.tm_year = 2012 - 1900; /* 2012年 */
tx.tm_mon = 2 - 1; /* 2月 */
tx.tm_mday = 1; /* 1日 */
tx.tm_hour = 0; /* 0時 */
tx.tm_min = 0; /* 0分 */
tx.tm_sec = 0; /* 0秒 */
tx.tm_isdst = 0; /* 夏時間無 */
tt = mktime( &tx );

puts(ctime( &tt ));
tt = tt + ((time_t)30 * 3600 * 24); /* 30日ずらす場合 3600秒24時間 */
puts(ctime( &tt ));

return 0;
}

/*
結果
Wed Feb 01 00:00:00 2012
Fri Mar 02 00:00:00 2012
*/

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

5文字以上入力してください

別のキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。