C言語関係掲示板

過去ログ

No.617.西暦1年から何秒?

[戻る] [ホームページ]
No.5988

西暦1年から何秒?
投稿者---Gen(2003/04/27 01:30:50)


西暦1年から今は、いったい何秒たっているのかというプログラムを組みました。しかし、これが正しいのかどうか確かめる方法がありません。
このソースで正しいのでしょうか?また、もう少しエレガントに書けるところなどはありませんでしょうか?
私の環境はsolaris8でのgccです。

/* Anno_Domini.c */
#include <stdio.h>
#include <time.h>



/*** Terminal Size(Standard) ***/
#define MAX_ROW         80
#define MAX_COL         24

/*** Terminal Size(Max) ***/
//#define MAX_ROW         176
//#define MAX_COL         57

/*** Escape Sequence ***/
#define Locate(x, y)   printf("\x1b[%d;%dH", y ,x)

int LeapYear(int year)
{
  if((!(year%4) && (year%100)) || !(year%400)) return 1;
  return 0;
}

double All_Sec(int year)
{
  int i, day=0, hour=0;
  double sec=0.0;

  for(i = 1; i <= year; i++){
    if(LeapYear(i)) day+= 366;
    else day+= 365;
  }
  sec = day * 24.0 * 3600.0;

  return sec;
}

int main(void)
{
  int i;
  int sec, min, hour, day, mon, year, date;
  int month_day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  double all_sec = 0.0;
  struct tm *tptr;
  time_t now;

  now  = time(NULL);
  tptr = localtime(&now);

  year = tptr->tm_year+1900;
  mon  = tptr->tm_mon;
  day  = tptr->tm_mday;
  hour = tptr->tm_hour;
  min  = tptr->tm_min;
  sec  = tptr->tm_sec;

  all_sec = All_Sec(year - 1);

  if(LeapYear(year+1)) month_day[1] = 29;
  else month_day[1] = 28;

  for(i = 0; i < mon; i++) date+= month_day[i];
  all_sec+= (date + day) * 24.0 * 3600.0 + hour * 3600.0 + min * 60.0 + sec;

  system("clear");

  Locate((MAX_ROW - 31)/2, MAX_COL/2-1);
  puts("Total time from A.D 1 until Now");

  while(1){
    Locate((MAX_ROW - 11)/2, MAX_COL/2);
    printf("%.0lf\n", all_sec);
    sleep(1);
    all_sec+= 1.0;
  }

  return 0;
}



No.5990

Re:西暦1年から何秒?
投稿者---かずま(2003/04/27 15:53:03)


> 西暦1年から今は、いったい何秒たっているのかというプログラムを組みました。
> しかし、これが正しいのかどうか確かめる方法がありません。
> このソースで正しいのでしょうか?

正しくありません。
現在のグレゴリオ暦(4、100、400年に一度閏年で補正する暦)が使われるよう
になったのは、1582年のローマ法王グレゴリオ13世によるもので、それまでは
ユリウス暦(4年に一度補正する)でした。さらに、このグレゴリオ暦への移行の
時期は各国で異なり、イギリスは 1752年、日本は 1873年です。

さらに、現在は、閏秒をどう扱うかも問題ですね。


> 私の環境はsolaris8でのgccです。

Unix だったら、cal 1752 を実行して、9月のカレンダーを見てください。

No.5993

Re:西暦1年から何秒?
投稿者---Gen(2003/04/27 17:29:31)


おっしゃるとおり、calを実行すると9月のカレンダーがずれていました。
以下のように訂正したのですが、これでいいのでしょうか?
11日間ずれていたので、それを引きました。
また、閏秒は現在までに22回挿入されていたみたいですが、
UTC開始以前に10秒のずれが生じていたようなので、32を足してみました。

  ・
  ・
  ・
Clear();
all_sec-=11*24.0*3600.0;
all_sec+=32.0;

Locate((MAX_ROW - 31)/2, MAX_COL/2-1);
puts("Total time from A.D 1 until Now");

while(1){
  ・
  ・ 
  ・
 

No.5995

Re:西暦1年から何秒?
投稿者---かずま(2003/04/27 21:18:31)


> おっしゃるとおり、calを実行すると9月のカレンダーがずれていました。
> 以下のように訂正したのですが、これでいいのでしょうか?
> 11日間ずれていたので、それを引きました。

それだけではダメですよ。グレゴリオ暦に移行する前はユリウス暦ですから、
100年に一度平年になるという規則を適用するのは間違いです。

No.6003

Re:西暦1年から何秒?
投稿者---Gen(2003/04/28 00:20:24)


>100年に一度平年になるという規則を適用するのは間違いです。
/*** Check a Leap Year ***/
int LeapYear(int year)
{
if(year <= 1582)
if(!(year%4)) return 1;
else if((!(year%4) && (year%100)) || !(year%400)) return 1;
return 0;
}

このような感じでしょうか?

No.6009

Re:西暦1年から何秒?
投稿者---Gen(2003/04/28 11:47:07)


>>100年に一度平年になるという規則を適用するのは間違いです。
よくよく考えてみるとおかしな気がしてきました。
1751年まででユリウス暦でのうるう年のカウントが437回、グレゴリオ暦でのカウントが424回です。
1752年はユリウス暦でもグレゴリオ暦でもうるう年の計算になりますが、
イギリスでグレゴリオ暦が開始されたのが1752年からですので、グレゴリオ暦でのカウントとすると、グレゴリオ暦の合計は425回です。
437日間と425日間では11日間のひらきがあります。これが、1752年9月のずれになるのだと思います。以下に、cal 1752 の実行結果を示します。

    9
日 月 火 水 木 金 土
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

ですので、11日間引くだけで、ユリウス暦とグレゴリオ暦の誤差を修正できているのではないのでしょうか?


No.6013

Re:西暦1年から何秒?
投稿者---かずま(2003/04/28 13:17:46)


> 1751年まででユリウス暦でのうるう年のカウントが437回、
> グレゴリオ暦でのカウントが424回です。
> 1752年はユリウス暦でもグレゴリオ暦でもうるう年の計算になりますが、
> イギリスでグレゴリオ暦が開始されたのが1752年からですので、
> グレゴリオ暦でのカウントとすると、グレゴリオ暦の合計は425回です。
> 437日間と425日間では11日間のひらきがあります。
> これが、1752年9月のずれになるのだと思います。

イギリスとその植民地で、グレゴリオ暦が開始されたのは、1752年9月14日
からですから、1752年はユリウス暦でも閏年とカウントされます。
1752年9月2日まででユリウス暦でのうるう年のカウントは、438回。
1752年9月2日までのグレゴリオ暦でのうるう年のカウントは、425回。
437日と425日では13日のひらきがあるのに、なぜか 9月3日を 9月14日に
読み替えるという、11日のひらきにしか採用しなかったのかは疑問です。


さて、単純にグレゴリオ暦が西暦1年から使われたとして、
西暦1年1月1日から1752年12月31日までの日数を計算してみましょう。
4で割り切れる年は、438回。
100で割り切れる年は、17回。
400で割り切れる年は、4回。
日数は、365*1752 + 438 - 17 + 4 = 639905日。

イギリスでは、実際にどうだったかというと、
西暦1年1月1日から1751年12月31日までの日数は、
4で割り切れる年が 437回だから、365*1751 + 437 = 639552日。
1752年は 366 - 11 = 355日しかないから、
西暦1年1月1日から1752年12月31日までの日数は、639552 + 355 = 639907日。

その差は、639907 - 639905 = 2

補正するのは 11 ではなく 2 ではありませんか。

なお、私は最初の問題を勘違いしていて、任意の日付、たとえば、
1234年5月6日は、西暦1年1月1日から何日か(あるいは何秒か)という問題だと
思っていました。それなら、1752年9月2日まではユリウス暦で計算しなければ
ならないということです。
現在の日時が西暦1年1月1日から何日かを求めるだけなら、全部グレゴリオ暦
で計算して、補正を加えれば十分だと思います。

No.6014

Re:西暦1年から何秒?
投稿者---Gen(2003/04/28 15:03:54)


>1752年9月2日まででユリウス暦でのうるう年のカウントは、438回。
>1752年9月2日までのグレゴリオ暦でのうるう年のカウントは、425回。
>437日と425日では13日のひらきがあるのに、なぜか 9月3日を 9月14日に
 ↑438日の間違いではありませんか?
それに、437日と425日のひらきは11日でよいのではないでしょうか?
おっしゃるとおりに、私も計算してみましたが同じで結果でした。
しかし、438日と425日では、438-425=12日のひらきがあります。

>読み替えるという、11日のひらきにしか採用しなかったのかは疑問です。


>その差は、639907-639905=2
>補正するのは11ではなく2ではありませんか
これも、639907-639905=1で1日のひらきではありませんか?
よって、合計で補正しなければならない日数は11日も含めると、12日になるような気がするのですが。


No.6057

Re:西暦1年から何秒?
投稿者---Gen(2003/04/30 01:51:15)


問題を難しく考えすぎていたかも知れません。
そもそも、1752年9月で、11日間の短縮をし、ユリウス暦と
グレゴリオ暦の誤差を修正したので、西暦1年から今現在の
経過秒数を考える場合は、すべてグレゴリオ暦の4,100,400で
考えればいいような気がします。
ですので、閏秒のみの考慮でいいのではないでしょうか?

また、以前、1752の11日間のひらきがおかしいのでは?との指摘が
ありましたが、あれはやはり、11日間で正しいと思います。
1752年のうるう年をグレゴリを暦でもカウントし、ユリウス暦でも
カウントしているので、かずまさんはたぶん誤解されているのではないでしょうか?
私が、以前書き込みをしたように、1752年をグレゴリオ暦のみの
カウントとすると11日間の開きになりますし、ダブってカウントするのはやはりまずいと思いますが・・・。
そのあたり、どう思いますか?


No.6062

Re:西暦1年から何秒?
投稿者---カンナ(2003/04/30 11:05:56)
http://hana.sakura.ne.jp/~elfin/k/


 すべてグレゴリオ暦で考えるのなら11日の補正も必要ないかと思います。

 ユリウス暦とグレゴリオ暦がずれているのは(何日間ずれているのかは
導入の時期に依りますが)ユリウス暦が閏日(など)を挿入し過ぎていた
からです。ではなにに対して挿入しすぎていたかというと本来の回帰年に
対してです。ということはグレゴリオ暦が本来の回帰年を正しく再現して
いると仮定するならば、ユリウス暦のキリスト紀元1年の1月1日とグレ
ゴリオ暦の1年1月1日は一致するのではないでしょうか?

 閏秒についてはグレゴリオ暦が持つ本来の回帰年に対するずれを補正し
ているものですから、考慮の必要があるかと思います。

No.6063

Re:西暦1年から何秒?
投稿者---カンナ(2003/04/30 11:24:05)
http://hana.sakura.ne.jp/~elfin/k/


 ユリウス日を用いるという手もあるかと思われます。

No.6082

Re:西暦1年から何秒?
投稿者---Gen(2003/04/30 23:15:19)


少し長くなりますが, 1752 年を境にうるう年をユリウス歴とグレゴリオ歴
で分けた場合と, すべてグレゴリオ歴でカウントしたものを比べてみました.
どちらも, 閏秒として32 秒を加えています.
私の環境(solaris 8, gcc)ではどちらも, 同じ結果になりました.


ユリウス歴とグレゴリオ歴の誤差(11 日間)を計算したプログラム

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

/*** Terminal Size(Standard) ***/
#define MAX_ROW         80
#define MAX_COL         24

/*** Terminal Size(Max) ***/
//#define MAX_ROW         176
//#define MAX_COL         57

/*** Escape Sequence ***/
#define Locate(x, y)   printf("\x1b[%d;%dH", y ,x)
#define Clear(void)    printf("\033[2J")



/*** Total Seconds ***/
double All_Sec(int year)
{
  int i, day=0, hour=0;
  double sec=0.0;

  for(i = 1; i <= year; i++){
    if(LeapYear(i)) day+= 366;
    else day+= 365;
  }
  sec = day * 24.0 * 3600.0;

  return sec;
}

/*** Check a Leap Year ***/
int LeapYear(int year)
{
  if(year < 1752 && !(year%4)) return 1;
  else if(year >= 1752 && ((!(year%4) && (year%100)) || !(year%400))) return 1;
  return 0;
}

int main(void)
{
  int i;
  int sec, min, hour, day, mon, year, date;
  int month_day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  double all_sec = 0.0;
  struct tm *tptr;
  time_t now;

  now  = time(NULL);
  tptr = localtime(&now);

  year = tptr->tm_year+1900;
  mon  = tptr->tm_mon;
  day  = tptr->tm_mday;
  hour = tptr->tm_hour;
  min  = tptr->tm_min;
  sec  = tptr->tm_sec;

  all_sec = All_Sec(year - 1);

  if(LeapYear(year+1)) month_day[1] = 29;
  else month_day[1] = 28;

  for(i = 0; i < mon; i++) date+= month_day[i];
  all_sec+= (date + day) * 24.0 * 3600.0 + hour * 3600.0 + min * 60.0 + sec;

  Clear();

  all_sec+=32.0;

  Locate((MAX_ROW - 31)/2, MAX_COL/2-1);
  puts("Total time from A.D 1 until Now");

  while(1){
    Locate((MAX_ROW - 15)/2, MAX_COL/2);
    printf("%.0lf/sec\n", all_sec);
    sleep(1);
    all_sec+= 1.0;
  }

  return 0;
}



グレゴリオ歴でカウントしたプログラム(変更した関数のみ)

/*** Check a Leap Year ***/
int LeapYear(int year)
{
  if((!(year%4) && (year%100)) || !(year%400)) return 1;
  return 0;
}


main関数の変更個所
.
.
.
Clear();
all_sec-=11*24.0*3600.0;
all_sec+=32.0;
.
.
.
}

No.6085

Re:西暦1年から何秒?
投稿者---カンナ(2003/05/01 02:37:29)
http://hana.sakura.ne.jp/~elfin/k/


>グレゴリオ歴でカウントしたプログラム(変更した関数のみ
(中略)
>main関数の変更個所
>  .
>  .
>  .
>  Clear();
>  all_sec-=11*24.0*3600.0;
>  all_sec+=32.0;
>  .
>  .
>  .
>}
 これは逆じゃないですか? ユリウス暦を用いたときに補正しグレゴリオ暦
のみの場合には補正しないのが本来だと思います。
 ただしこのとき(かずまさんが指摘された通り)2日間のずれが生じますね。
すなわちユリウス暦を用いた場合の方がグレゴリオ暦のみを用いた場合に比べ
て2日間長くなります。1日分はキリスト紀元4年に閏日が設けられなかった
にも関わらずこのプログラムではそれを考慮していないのが原因だとして、も
う1日についてはよくわかりません。グレゴリオ暦の日付を決定する際に基準
となったのが「春分の日を3月21日とする」というものであってキリスト紀元
の1年1月1日ではないことに由来するのではないかと邪推します。
 これを基にして、「西暦元年1月1日」の定義が「今から2002年前のローマ
帝国におけるJanuarius1日」とするならば、ユリウス暦を用いてキリスト紀元
4年の閏日を除いたもの、同じことですがグレゴリオ暦のみを用いて1日加算
したものが正しい経過日になると思います。
 ただし上記の「もう1日」のずれがキリスト紀元1年以後のユリウス暦に含
まれている場合にはグレゴリオ暦そのままでよくなるでしょう。この1日につ
いては残念ながら調べがつきませんでした。

No.6090

Re:西暦1年から何秒?
投稿者---Gen(2003/05/01 16:49:49)


>これは逆じゃないですか? ユリウス暦を用いたときに補正しグレゴリオ
おっしゃるとおり、逆に書いてしまいました。すいません。
しかし、遊びで作るつもりが、かなり深く西暦について知識が深まって、嬉しい誤算って感じです。
西暦ひとつとっても、奥が深いですね。
私も、もう少し勉強してみます。
どうも、ありがとうございました。