Dev-C++ 4.9.9.2
gcc version 3.4.2 (mingw-special)
です。
UNIX時間と普通の日付時刻(西暦a年b月c日 d時e分f秒)とを相互変換するプログラムを作っています。
現在のソースコードはこれです。
utconvert.h
/*utconvert.h*/
#ifndef UTCONVERT_H_GUARD
#define UTCONVERT_H_GUARD
typedef struct {
int year;
int month;
int date;
int hour;
int minute;
int second;
} ut2date_date_t;
long long date2ut(int year,int month,int date,
int hour,int minute,int second);
void ut2date(ut2date_date_t* result,long long unixTime);
#endif
#include "utconvert.h"
/*1日の秒数(=24*60*60)*/
#define SECONDS_PER_DAY 86400
/*1年からyear年まで(両端を含む)の日数を求める*/
static long long getDays(int year) {
long long result;
if(year<0)return -getDays(-year)-366+365;
else if(year==0)return 0;
result=year*365;/*1年は基本365日*/
result+=year/4;/*4で割り切れたら閏年*/
result-=year/100;/*100で割り切れたら閏年ではない*/
result+=year/400;/*400で割り切れたら閏年*/
return result;
}
/*1970年1月1日 00:00:00からの経過秒数を返す*/
long long date2ut(int year,int month,int date,
int hour,int minute,int second) {
const int monthDays[13]={
0,31,59,90,120,151,181,212,243,273,304,334,365
};/*その月までの日数の和(累積和)*/
long long result;
/*アクセス違反になる不正入力なら0を返す*/
if(month<1 || month>12)return 0;
/* year年1月1日 00:00:00までの日数を求める*/
result=getDays(year-1)-getDays(1969);
/*秒に変換*/
result*=SECONDS_PER_DAY;
/*月の日数を秒に変換して足す*/
result+=monthDays[month-1]*SECONDS_PER_DAY;
/*閏年かつ3月以降なら1日足す*/
if(year%400==0 || (year%4==0 && year%100!=0)) {
if(month>=3)result+=SECONDS_PER_DAY;
}
/*その月の日数を秒に変換して足す*/
result+=(date-1)*SECONDS_PER_DAY;
/*時間を足す*/
result+=hour*60*60;
/*分を足す*/
result+=minute*60;
/*秒を足す*/
result+=second;
/*結果を返す*/
return result;
}
/*1年からyear年までの閏年の個数を求める*/
static int getLeapYearNum(int year) {
int result;
if(year<0)return -getLeapYearNum(-year)-1;
else if(year==0)return 0;
result=year/4;/*4で割り切れたら閏年*/
result-=year/100;/*100で割り切れたら閏年ではない*/
result+=year/400;/*400で割り切れたら閏年*/
return result;
}
/*その年が閏年であるかを求める*/
static int isLeapYear(int year) {
if(year%400==0 || (year%4==0 && year%100!=0))return 1;
return 0;
}
/*1970年1月1日 00:00:00からの経過秒数を日付にする*/
void ut2date(ut2date_date_t* result,long long unixTime) {
int monthDays[13]={
0,31,59,90,120,151,181,212,243,273,304,334,365
};/*その月までの日数の和(累積和)*/
int i;
long long days;
int yearNum;
int amariDays;
int daySeconds;
int hoseiYear;
if(!result)return;
if(unixTime>=0) {
days=unixTime/SECONDS_PER_DAY;
daySeconds=(int)(unixTime%SECONDS_PER_DAY);
yearNum=1970+(int)(days/365);
amariDays=(int)(days%365);
} else {
days=(-unixTime)/SECONDS_PER_DAY;
daySeconds=(int)(SECONDS_PER_DAY-((-unixTime)%SECONDS_PER_DAY));
if(daySeconds==SECONDS_PER_DAY) {
daySeconds=0;
} else days++;
yearNum=1970-(int)(days/365)-1;
amariDays=365-(int)(days%365);
}
amariDays-=getLeapYearNum(yearNum-1)-getLeapYearNum(1969);
while(1) {
if((amariDays>=0 && amariDays<365) ||
(amariDays==365 && isLeapYear(yearNum)))break;
if(amariDays<0) {
hoseiYear=(-amariDays)/365+1;
amariDays+=hoseiYear*365;
amariDays+=getLeapYearNum(yearNum-1)-
getLeapYearNum(yearNum-hoseiYear-1);
yearNum-=hoseiYear;
} else if(amariDays>=365) {
hoseiYear=amariDays/365;
amariDays=amariDays%365;
amariDays-=getLeapYearNum(yearNum+hoseiYear-1)-
getLeapYearNum(yearNum-1);
yearNum+=hoseiYear;
} else break;
}
if(isLeapYear(yearNum)) {
for(i=2;i<=12;i++)monthDays[i]++;
}
for(i=1;i<=12;i++) {
if(amariDays>=monthDays[i-1] && amariDays<monthDays[i])break;
}
amariDays-=monthDays[i-1];
result->year=yearNum;
result->month=i;
result->date=amariDays+1;
result->hour=daySeconds/3600;
result->minute=(daySeconds/60)%60;
result->second=daySeconds%60;
}
現状のプログラムで、このJavaScriptのコードといくつかの入力に対する出力を比較したところ、
見た範囲では一致しているようです。
► スポイラーを表示
また、もっといい(見た目が美しい、わかりやすい、効率が良いなど)書き方はありますでしょうか?
お教えていただければ幸いです。
よろしくお願いします。
C言語で、標準ライブラリ(time.hの関数を含む)は使用禁止でお願いします。