"date_in_English": Date notation in English utilities in C
hacker emblem Happy Hacking!


English Here (machine translation)

date_in_English: 西暦日付を扱うユーティリティ

この C 言語ユーティリティは、A.D.1 年 1 月 1 日からA.D.4294967295 年 12 月 31 日までの西暦日付を扱うためのユーティリティです。
このユーティリティには、次のマクロと API を含みます。

API を使用するためのヘッダは days.h で、API の実装は days.c です。API の説明は、この文書で後述しています。

テスト・プログラム days-test.c そして make ファイル Makefile を記述しました。


API の説明

  1. 半角数字文字列が西暦日付として正当であることを判定する is_valid_date()
    int is_valid_date(char *date, size_t sz);

    date には "yyy...yyymmdd" 形式の半角数字文字列を指定します。
    sz には date の文字列長を指定します。

    "yyy...yyy" に "0" から "4294967295" までの数字列を指定した場合、正当な西暦年であると判定します。ただし、"0" から "999" までの文字列の場合は、西暦 2000 年代を指定したものと解釈します。西暦 1 年から 999 年までを指定するには、"0001" から "0999" とゼロ詰めの半角数字列とする必要があります。

    戻り値は以下の意味を持ちます。

    • DAYS_ILLEGAL_ARGS (= -1) : 不正な引数が渡された場合
    • DAYS_FALSE (= 0) : 西暦日付として不当な文字列の場合
    • DAYS_TRUE (= 1) : 西暦日付として正当な文字列の場合

  2. 西暦日付として正当である半角数字文字列から西暦年、月、日を表す正整数を求める get_ymd() and days_count_to_ymd()
    int get_ymd(char              *date
    , size_t sz
    , unsigned long *year
    , int *month
    , int *day
    );
    int days_count_to_ymd(long long day_count
    , unsigned long *year
    , int *month
    , int *day
    );

    date には "yyy...yyymmdd" 形式の半角数字文字列を指定します。date が指す文字列が西暦日付として正当であることの定義は、is_vaid_date() と同じです。
    day_count には days_count() の戻り値と同様な西暦通算日数を渡します。
    sz には date の文字列長を指定します。
    year には date から求めた西暦年を出力する符号なし 4 バイト整数のアドレスを渡します。
    month には date から求めた月を出力する整数のアドレスを渡します。
    day には date から求めた日を出力する整数のアドレスを渡します。

    戻り値は以下の意味を持ちます。

    • DAYS_ILLEGAL_ARGS (= -1) : 不正な引数が渡された場合
    • 0 : 処理が正常に終了した場合

  3. 半角数字文字列を英語表記の西暦日付に変換する date_in_English()
    char *date_in_English(char *date
    , size_t sz
    , DAYS_FMT fmt
    , char *str
    , size_t str_sz
    );

    date には "yyy...yyymmdd" 形式の半角数字文字列を指定します。
    sz には date の文字列長を指定します。
    fmt には DAYS_FMT_EUROPEAN あるいは DAYS_FMT_AMERICAN のいずれかを指定します。fmt に DAYS_FMT_EUROPEAN を指定すると "<dd>, <月の英語名> <yyy..yyy>" に、DAYS_FMT_AMERICAN を指定すると "<月の英語名> <dd>, <yyy...yyy>" に変換します。
    str には変換後の文字列を出力します。
    str_sz には str が指すメモリ領域のサイズを指定します。

    "yyy...yyy" には is_valid_date() と同じ制限を持ちます。

    戻り値は以下の意味を持ちます。

    • NULL : 不正な引数が渡された場合
    • NULL 以外のアドレス : 変換後の文字列アドレス (str と同じアドレス)

  4. その年の何日目かを求める get_day_of_year()
    int get_day_of_year(char *date, size_t sz);

    date には "yyy...yyymmdd" 形式の半角数字文字列を指定します。
    sz には date の文字列長を指定します。

    "yyy...yyy" には is_valid_date() と同じ制限を持ちます。

    戻り値は以下の意味を持ちます。

    • ゼロ : 不正な引数が渡された場合
    • 1 以上の整数 : その西暦年の何日目であるかの値

  5. 西暦日付の通算日数を求める days_count()
    long long days_count(char *date, size_t sz);

    date には "yyy...yyymmdd" 形式の半角数字文字列を指定します。
    sz には date の文字列長を指定します。

    "yyy...yyy" には is_valid_date() と同じ制限を持ちます。

    戻り値は以下の意味を持ちます。

    • LLONG_MIN : 不正な引数が渡された場合
    • 1 以上の整数 : 西暦 1 年 1 月 1 日の場合を 1 とする西暦通算日数。最大値は MAX_DAYS_COUNT (=1568704592244LL)。

  6. days_count() で求めた西暦日付の通算日数をベースとする整数値を日付を表す 8 桁以上の数字文字列に変換しなおす days_count_to_date_str()
    char *days_count_to_date_str(long long day_count
    , char *date
    , size_t sz
    );

    day_count には days_count() で求めた西暦日付の通算日数をベースとする 1 以上の整数値を指定します。
    date には "yyyy...mmdd" 形式の 8 桁以上の半角数字文字列を出力できるバッファのアドレスを指定します。
    sz には date のバッファ・サイズを指定します。

    date に出力される半角数字文字列は、sz に指定されたバッファ・サイズが不足している場合を除いて、is_valid_date() と同じ制限を満たします。

    戻り値は以下の意味を持ちます。

    • NULL : 不正な引数が渡された場合 (errno に EINVAL を出力します)
    • 非 NULL : 正常に終了した場合 (date に指定されたアドレスになります)

  7. 西暦日付の曜日を求める day_of_week(), day_of_week_str() and get_day_of_week()
    Day_of_week_e day_of_week(Days_counts);
    char *day_of_week_str(long long days_counts);
    char *get_day_of_week(char *date, size_t sz);

    Days_counts あるいは days_counts 引数に days_count() の戻り値を渡されると、曜日を表す列挙型値 (Day_of_week_e 型) に変換するマクロ day_of_week() と曜日を表す英語表記文字列のアドレスに変換する day_of_week_str() API、そして、date に西暦日付を表す半角数字文字列と sz に date の文字列長を渡されると、曜日を表す英語表記文字列のアドレスに変換する get_day_of_week() API です。

    Day_of_week_e 型は enum 型として以下のように定義されています。

    Sunday    = 0 /* 日曜日 */
    Monday = 1 /* 月曜日 */
    Tuesday = 2 /* 火曜日 */
    Wednesday = 3 /* 水曜日 */
    Thursday = 4 /* 木曜日 */
    Friday = 5 /* 金曜日 */
    Saturday = 6 /* 土曜日 */
    Illegal_day_of_week = 7 /* 不正な引数 */

    不正な引数 (負数) を渡されると、day_of_week() マクロは定数 Illegal_day_of_week を返し、day_of_week_str() API は NULL を返します。

  8. ふたつの西暦日付の経過日数を求める diff_dates()
    long long diff_dates(char *date1
    , size_t sz1
    , char *date2
    , size_t sz2
    );

    date1 と date2 には "yyy...yyymmdd" 形式の半角数字文字列を指定します。
    sz1 と sz2 には date1 と date2 それぞれの文字列長を指定します。

    "yyy...yyy" には is_valid_date() と同じ制限を持ちます。

    戻り値が LLONG_MIN 以外の値を返した場合、その値は date1 と date2 の経過日数になります。

    • LLONG_MIN : 不正な引数が渡された場合
    • LLONG_MIN より大きな負の整数 : date1 が date2 より過去の西暦日付の場合
    • ゼロ : date1 と date2 が同じ西暦日付である場合
    • ゼロより大きな正の整数 : date1 が date2 より未来の西暦日付の場合

  9. ある日付を規準とした去年、今月、来週などの期間を求める calc_duration() and get_duration()
    Duration_t *calc_duration(char       *date
    , Duration_unit_e unit
    , long long delta
    , Duration_t *duration
    );
    Duration_t *get_duration(long long day_count
    , Duration_unit_e unit
    , long long delta
    , Duration_t *duration
    );

    date には期間の算出の基準となる日付を表す "yyy...yyymmdd" 形式の半角数字文字列を指定します。
    day_count には days_count() の戻り値と同様な西暦通算日数を渡します。
    unit には求める期間の単位により、年であれば Duration_unit_Years を、月であれば Duration_unit_Months を、週であれば Duration_unit_Weeks を指定します。
    delta には unit で指定した期間の単位で date からの相対時間を指定します。ゼロを指定すると今年、今月あるいは今週にあたる期間を求め、負数を指定すると去年、先月あるいは先週以前の期間を求め、正数を指定すると来年、来月あついは来週以降の期間を求めます。
    duration には求めた期間を出力する Duration_t 構造体のアドレスを渡します。Duration_t 構造体は以下のメンバを持ちます。

    • long long begin_of : 期間の最初の日付に相当する西暦通算日数 (days_count() の戻り値と同じ計数値)
    • long long end_of : 期間の最後の日付に相当する西暦通算日数 (days_count() の戻り値と同じ計数値)
    • long long days : 期間の日数 (end_of - begin_of + 1 に等しい値)

    戻り値は以下の意味を持ちます。

    • NULL : 不正な引数が渡された場合
    • 非 NULL : 指定された期間を正常に求めた場合 (duration の値に等しい)

  10. 二つの期間の包含関係も併せた比較を行う compare_durations()
    typedef enum duration_Inclusive_e {
    Duration_has_no_intersect_dur1_is_on_left_of_dur2 = -2
    , Duration_has_intersect_dur1_is_on_left_of_dur2
    , Duration_has_intersect_dur_contains_the_other
    , Duration_has_intersect_dur1_is_on_right_of_dur2
    , Duration_has_no_intersect_dur1_is_on_right_of_dur2
    } Duration_Inclusive_e;
    int compare_durations(Duration_t           *dur1
    , Duration_t *dur2
    , Duration_Inclusive_e *cmp_result
    , Duration_t *closure
    , Duration_t *intersection
    );

    dur1 と dur2 には包含関係も含めた比較を行う期間を指定します。
    closure には dur1 と dur2 を両方とも包含する最小の期間を出力します。
    cmp_result への出力値は次の意味を持ちます。

    • Duration_has_no_intersect_dur1_is_on_left_of_dur2 (= -2) の場合、dur1 と dur2 は交差しておらず dur1 は dur2 よりも過去の期間になっています。
    • Duration_has_intersect_dur1_is_on_left_of_dur2 (= -1) の場合、dur1 と dur2 は交差しており dur1 の開始日付 (begin_of) は dur2 よりも過去の日付になっています。
    • Duration_has_intersect_dur_contains_the_other (= ゼロ) の場合、dur1 と dur2 は一方がもう一方に包含されています。
    • Duration_has_intersect_dur1_is_on_right_of_dur2 (= 1) の場合、dur1 と dur2 は交差しており dur1 の開始日付 (begin_of) は dur2 よりも未来の日付になっています。
    • Duration_has_no_intersect_dur1_is_on_right_of_dur2 (= 2) の場合、dur1 と dur2 は交差しておらず dur1 は dur2 よりも未来の期間になっています。

    cmp_result の出力値により intersection へ出力される期間は、次のように変わります。

    • cmp_result が Duration_has_no_intersect_dur1_is_on_left_of_dur2 あるいは Duration_has_no_intersect_dur1_is_on_right_of_dur2 のいずれかである場合、intersection に出力される期間は closure の期間から dur1 と dur2 の期間を除いたもの (つまり、closure≡{dur1 ∪ intersection ∪ dur2} ) になります。
    • cmp_result が Duration_has_no_intersect_dur1_is_on_left_of_dur2 あるいは Duration_has_no_intersect_dur1_is_on_right_of_dur2 のいずれかでもない場合、intersection に出力される期間は dur1 が dur2 交差する期間 (つまり、closure≡{dur1 ∪ dur2} で intersection≡{dur1 ∩ dur2} ) になります。

    戻り値は以下の意味を持ちます。

    • 非ゼロ : 不正な引数が渡された場合
    • ゼロ : 処理が正常に終了した場合