« さくらメロディ | トップページ | JBOOK: コミック / ベストセラー (2006年5月10日 5時46分現在)(BlogPet) »
2006.05.08
RFC822形式の日時に関する処理
RSS2.0の日時(pubDate、lastBuildDate?)にはRFC#822で定められた形式が使われています。これは可読性が高いものの時刻値同士の比較などが面倒なので、これを内部時刻値(1990/01/01 00:00:00 GMTからの経過秒数)やW3C形式に変換するために作成しました。
これを見て、大昔(1992年~1996年頃)に NetNews のオフラインリーダーを作ったときに、RFC822形式な日時を yyyymmdd HH:MM:SS とかに変換する処理を C で書いたなぁ、と思い出したので、今さら他人の役に立つかどうかわかりませんが、せっかくなので、当時のソースコードを公開しておきます。NetNews の世界では、微妙に RFC822 とはずれた形式で投稿される記事もある(たぶん、RFC822 をよく読まずに作られた投稿クライアントが存在するせい)ので、その辺にも対応できるように少し ad hoc なこともしています。最終更新は1999年4月27日なので、7年くらい、そのまま放置していることになりますね。
/*
* change date format
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
static char month[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static int mdays[] = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
static struct timezone {
char name[5];
int diffHH;
int diffMM;
} tz[] = {
/* {"NZDT", 13, 0 }, $* New Zealand (Winter Time,30Oct1988-4Mar1989 only) */
/* { "???", 12, 45 }, $* New Zealand/Chatham Island */
{"NZST", 12, 0 }, /* New Zealand */
/* { "???", 10, 30 }, $* Australia/LHI */
/* { "EST", 10, 0 }, $* Australia/Tasmania, Queensland, Victoria, NSW */
/* { "CST", 9, 30 }, $* Australia/North, South, Yancowinna */
/* { "WST", 8, 0 }, $* Australia/West */
{ "KDT", 10, 0 }, /* Republic of Korea (Summer Time, since 1987) */
{ "KST", 9, 0 }, /* Republic of Korea */
{ "JST", 9, 0 }, /* Japanese Standard Time */
/* { "CDT", 9, 0 }, $* People's Republic of China (SummerTime,since 1970)*/
/* { "CST", 8, 0 }, $* People's Republic of China, Republic of China */
{ "HKT", 8, 0 }, /* Hongkong */
{ "SST", 8, 0 }, /* Singapore */
{ "IDT", 4, 30 }, /* Iran (Summer Time, since 1988) */
{ "IST", 3, 30 }, /* Iran */
/* { "IDT", 3, 0 }, $* Israel (10 Apr - 3 Sep in Hebraic Calendar) */
/* { "IST", 2, 0 }, $* Israel */
/* { "EET", 3, 0 }, $* Turkey */
{ "EET", 2, 0 }, /* Egypt, Lybia, East Europe */
{ "MET", 1, 0 }, /* Poland, Medium Europe */
{ "CET", 1, 0 }, /* Central European Time */
{ "BST", 1, 0 }, /* British Summer Time */
{ "GMT", 0, 0 }, /* Greenwich Mean Time */
{ "WET", 0, 0 }, /* Iceland, West Europe */
{ "EDT", -4, 0 }, /* USA/Eastern (Summer Time) */
{ "EST", -5, 0 }, /* USA/Eastern, East-Indiana, Michigan */
{ "CDT", -5, 0 }, /* USA/Central (Summer Time) */
{ "CST", -6, 0 }, /* USA/Central */
{ "MDT", -6, 0 }, /* USA/Mountain (Summer Time) */
{ "MST", -7, 0 }, /* USA/Mountain, Arizona, Navajo */
{ "PDT", -7, 0 }, /* USA/Pacific (Summer Time) */
/* {"PPET", -7, 0 }, $* USA/Pacific-New (Presidential Election Year only) */
{ "PST", -8, 0 }, /* USA/Pacific, Pacific-New */
{"AKST", -9, 0 }, /* USA/Alaska */
{"AHST",-10, 0 }, /* USA/Alutian */
{"HAST",-10, 0 }, /* USA/Alutian (same as AHST */
{ "HST",-10, 0 }, /* USA/Hawaii */
/* { "HDT",-10,-30 }, $* USA/Hawaii (Summer Time, 1933 0nly) */
{ "NST",-11, 0 }, /* USA/Nome */
/* { "BST",-11, 0 }, $* USA/Bering */
/* { "SST",-11, 0 }, $* USA/Samoa */
{ "NDT", -2,-30 }, /* Canada/Newfoundland (Summer Time) */
/* { "NST", -3,-30 }, $* Canada/Newfoundland */
{ "ADT", -3, 0 }, /* Canada/Atlantic (Summer Time) */
{ "AST", -4, 0 }, /* Canada/Atlantic */
/* { "EDT", -4, 0 }, $* Canada/Eastern (Summer Time) */
/* { "EST", -5, 0 }, $* Canada/Eastern */
/* { "CDT", -5, 0 }, $* Canada/Central (Summer Time) */
/* { "CST", -6, 0 }, $* Canada/Central, East-Saskatchewan */
/* { "MDT", -6, 0 }, $* Canada/Mountain (Summer Time) */
/* { "MST", -7, 0 }, $* Canada/Mountain */
/* { "PDT", -7, 0 }, $* Canada/Pacific (Summer Time) */
/* { "PST", -8, 0 }, $* Canada/Pacific */
{ "YDT", -8, 0 }, /* Canada/Yukon (Summer Time) */
{ "YST", -9, 0 }, /* Canada/Yukon */
/* { "CST", -6, 0 }, $* Mexico/General */
/* { "MST", -7, 0 }, $* Mexico/BajaSur */
/* { "PDT", -7, 0 }, $* Mexico/BajaNorte (Summer Time, since 1987) */
/* { "PST", -8, 0 }, $* Mexico/BajaNorte */
/* { "CDT", -6, 0 }, $* Cuba (Summer Time. since 1981) */
/* { "CST", -5, 0 }, $* Cuba */
{ "FDT", -1, 0 }, /* Brazil/DeNoronha (Summer Time) */
{ "FST", -2, 0 }, /* Brazil/DeNoronha */
/* { "EDT", -2, 0 }, $* Brazil/East (Summer Time) */
/* { "EST", -3, 0 }, $* Brazil/East */
{ "WDT", -3, 0 }, /* Brazil/West (Summer Time) */
/* { "WST", -4, 0 }, $* Brazil/West */
/* { "ADT", -4, 0 }, $* Brazil/Acre (Summer Time) */
/* { "AST", -5, 0 }, $* Brazil/Acre */
/* { "CDT", -3, 0 }, $* Chile/Continental (Summer Time) */
/* { "CST", -4, 0 }, $* Chile/Continental */
/* { "EDT", -5, 0 }, $* Chile/Easter Island (Summer Time) */
/* { "EST", -6, 0 }, $* Chile/Easter Island */
{ "UCT", 0, 0 }, /* GMT */
{ "UTC", 0, 0 }
};
#define isleapyear(y) (((y)%4 == 0) && (((y)%100 != 0) || ((y)%400 == 0)))
long
daynum( yy, mm, dd )
int yy, mm, dd;
{
long day = 0;
day = dd;
mm--;
while ( yy >= 1970 ) {
while ( mm >= 1 ) {
day += mdays[mm-1];
if ( mm == 2 )
if ( isleapyear( yy ) )
day++;
mm--;
}
yy--;
mm = 12;
}
return ( (day-1) * 24 * 60 * 60 );
}
void
changeDtime( yy, mm, dd, HH, MM, SS, diffHH, diffMM )
int *yy, *mm, *dd, *HH, *MM, *SS, diffHH, diffMM;
{
long dtime = ((*HH * 60) + *MM) * 60 + *SS;
struct tm *tm;
dtime += daynum( *yy, *mm, *dd ) - (diffHH * 60 + diffMM) * 60;
/* change to GMT */
tm = localtime( &dtime ); /* change from GMT to local time */
*yy = tm->tm_year + 1900;
*mm = tm->tm_mon + 1;
*dd = tm->tm_mday;
*HH = tm->tm_hour;
*MM = tm->tm_min;
*SS = tm->tm_sec;
}
#define skipNumeric(p) \
while ( ( *p >= '0' ) && ( *p <= '9' ) ) \
p++
#define skipNonNumeric(p) \
while ( (*p) && ( ( *p < '0' ) || ( *p > '9' ) ) ) \
p++
#define skipWhiteSpace(p) \
while ( ( *p == ' ' ) || ( *p == '\t' ) ) \
p++
#define skipToNumeric(p) \
skipNonNumeric(p); \
if ( !(*p) ) \
return ( NULL )
#define skipToNonNumeric(p) \
skipNumeric(p); \
skipWhiteSpace(p); \
if ( !(*p) ) \
return ( NULL )
#define skipToNextNumeric(p) \
skipNumeric(p); \
skipNonNumeric(p); \
if ( !(*p) ) \
return ( NULL )
char *
changeDate( p )
register char *p;
{
static char dtime[BUFSIZ];
int yy, mm, dd, HH, MM, SS;
int i;
#if 0
char *q;
if ( ( q = strchr( p, ',' ) ) != NULL ) /* for `Wday, DD Month YY[YY]' */
p = q + 1;
else if ( ( q = strchr( p, ':' ) ) != NULL )
p = q + 1;
skipWhiteSpace(p);
#endif
skipToNumeric(p);
dd = atoi( p );
skipToNonNumeric(p);
mm = 0;
for ( i = 0; i < 12; i++ ) {
if ( !strncmp( p, month[i], 3 ) ) {
mm = i + 1;
break;
}
}
if ( mm == 0 )
return ( NULL );
skipToNumeric(p);
yy = atoi( p );
if ( yy < 100 ) {
if ( yy < 70 )
yy += 100;
yy += 1900;
}
skipToNextNumeric(p);
HH = atoi( p );
skipToNextNumeric(p);
MM = atoi( p );
skipToNextNumeric(p);
SS = atoi( p );
skipNumeric(p);
skipWhiteSpace(p);
if ( *p ) {
#ifdef DEBUG
printf( "%04d.%02d.%02d %02d:%02d:%02d", yy, mm, dd, HH, MM, SS );
#endif
if ( ( *p == '+' ) || ( *p == '-' ) ) {
int diffHH = atoi( p ) / 100;
int diffMM = atoi( p ) % 100;
changeDtime( &yy, &mm, &dd, &HH, &MM, &SS, diffHH, diffMM );
}
else {
int found = 0;
for ( i = 0; i < sizeof(tz)/sizeof(struct timezone); i++ ) {
if ( !strncmp( p, tz[i].name, 3 ) ) {
found = 1;
break;
}
}
if ( found ) {
if ( !strncmp( p + 3, " DST", 4 ) ) /* Daylight Saving Time */
changeDtime( &yy, &mm, &dd, &HH, &MM, &SS,
tz[i].diffHH+1, tz[i].diffMM );
else
changeDtime( &yy, &mm, &dd, &HH, &MM, &SS,
tz[i].diffHH, tz[i].diffMM );
}
#ifdef DEBUG
else
printf( " ???=" );
#endif
}
#ifdef DEBUG
printf( " %s => ", p );
#endif
}
sprintf( dtime, "%04d.%02d.%02d %02d:%02d:%02d", yy, mm, dd, HH, MM, SS );
#ifdef DEBUG
printf( "%s\n", dtime );
#endif
return ( dtime );
}
#ifdef TEST
void
main()
{
char *p, buf[BUFSIZ];
while ( ( p = fgets( buf, BUFSIZ - 1, stdin ) ) != NULL ) {
if ( p[strlen(p)-1] == '\n' )
p[strlen(p)-1] = NULL;
if ( !strncmp( p, "Date: ", 6 ) )
p += 6;
printf( "chdate: %s -> %s\n", p, changeDate( p ) );
}
}
#endif
ANSI C 以前の C コンパイラでもコンパイルできるように古い K&R スタイルで書いてあります。 あと、「Z、A、B、C、D、E、F、G、H、I、K、L、M、N、O、P、Q、R、S、T、U、V、W、X、Y」の1文字のタイムゾーンにも対応してない(実際に NetNews で使われているのを見たことがないので、対応しようとしなかったんだけど)ので、書き直した方がいいんだろうなぁ。
投稿者: tsupo 2006.05.08 午前 01:17
| 固定リンク
|
|
| ![]()
|
|
アマゾンわくわく探検隊
トラックバック
この記事のトラックバックURL:
この記事へのトラックバック一覧です: RFC822形式の日時に関する処理:
コメント
ないので少しや文字や古いスタイルを公開したかったの♪
投稿者: BlogPetのarimy (2006.05.13 午前 09:17)
こういった情報を提供していただける方を尊敬します^^
大変参考になりました!
投稿者: tm.nagata (2011.02.10 午前 09:16)



