RFC822形式の日時に関する処理

観測気球

収集物の記録書庫 a data archive of collection -- collectible toys

[要旨] まだ NetNews が Web よりメジャーだった頃に作ったものですが、今でもそれなりに使えると思いますので公開します。他の言語への移植も簡単だと思います。
[キーワード] RFC822,dateTime

« さくらメロディ | トップページ | 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形式に変換するために作成しました。

Perlメモ/RFC#822形式の日時の解析 - Walrus, Digit.

これを見て、大昔(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 | 固定リンク | このエントリーをはてなブックマークに追加 | このエントリを del.icio.us に登録 このエントリの del.icio.us での登録状況 | このエントリを Buzzurl に追加このエントリの Buzzurl での登録状況 | このエントリをlivedoorクリップに登録 このエントリのlivedoorクリップでの登録状況 このエントリをlivedoorクリップに登録している人の数 | 酢鶏巡回中

楽天市場


プログラミング」カテゴリ内の最近の記事

品揃え豊富で安い!NTT-X Store


アマゾンわくわく探検隊

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/6737/9954762

この記事へのトラックバック一覧です: RFC822形式の日時に関する処理:

コメント


ないので少しや文字や古いスタイルを公開したかったの♪


投稿者: BlogPetのarimy (2006.05.13 午前 09:17)


こういった情報を提供していただける方を尊敬します^^
大変参考になりました!

投稿者: tm.nagata (2011.02.10 午前 09:16)

コメントを書く




※イタズラ防止のため、メールアドレスを入力しないと投稿できません。

次からのコメント入力の手間を省くために、名前やメールアドレスをcookieに記憶しますか?


URL を入力すると、その URL にリンクがはられます。
なお、メールアドレスは公開されません。ご安心ください。


ワード

ニッセン

fujisan.co.jp

楽天市場