marunomaruno-memo

marunomaruno-memo

[C] 日付関係のユーティリティ

2012年06月11日 | Android
[C] 日付関係のユーティリティ
================================================================================

日付関係のユーティリティとして、次のようなものを作った。

関数の概要
---
time_t toSystemTime(char *dateString);          日付文字列をシステム時刻に変換
time_t toStrictSystemTime(char* dateString);    日付文字列をシステム時刻に変換
char* toDateString(char *dateString, time_t systemTime);    
                                                システム時刻を日付文字列に変換
char* toJaWeekString(char *weekString, time_t systemTime) 
                                システム時刻を曜日(日、月、...、土)文字列に変換
int isLeap(int year);                         year 年がうるう年か平年かを返す
int lastMonthDay(int year, int month);        year 年 month 月の最後の日付を返す
---

関数の詳細
---
time_t toSystemTime(char *dateString);

    日付文字列をシステム時刻に変換する。
    日付は、西暦年が 1901 以上、月は 1~12 の範囲、日は 1~31 の範囲内でなければ不
    正な日付とする。

    引数   dateString 日付を表す文字列("YYYYMMDD")

    戻り値 システム時刻(1970年1月1日 0時0分0秒からの経過時間(秒単位))。変換でき
		   ない場合、-1.


time_t toStrictSystemTime(char* dateString);

    日付文字列をシステム時刻に変換する。
    日付は、西暦年が1901以上とするが、厳密に月・日の範囲内でなければ不正な日付と
	する。

    引数   dateString 日付を表す文字列("YYYYMMDD")

    戻り値 システム時刻(1970年1月1日 0時0分0秒からの経過時間(秒単位))。変換でき
		   ない場合、-1.


char* toDateString(char *dateString, time_t systemTime);

    システム時刻を日付文字列に変換する。

    引数   systemTime システム時刻
    引数   dateString 日付を表す文字列を格納する文字列へのポインター

    戻り値 日付を表す文字列("YYYYMMDD")


char* toJaWeekString(char *weekString, time_t systemTime) {

    システム時刻を曜日(日、月、...、土)文字列に変換する。

    引数   systemTime システム時刻
    引数   weekString 曜日を表す文字列を格納する文字列へのポインター

    戻り値 曜日を表す文字列


int isLeap(int year);

    year年がうるう年か平年かを返す。

    引数   year 西暦年。正数を指定する。

    戻り値 うるう年のとき1、平年のとき0


int lastMonthDay(int year, int month);

    year年month月の最後の日付を返す。

    引数   year 西暦年
    引数   month 月。ただし、通常の月より1引いた値を使う(0~11)

    戻り値 year年month月の最後の日付
---


▲ 公開用ヘッダー

□ DateUtil.h
---
/*
 ============================================================================
 Name        : DateUtil.h
 Author      : marunomaruno
 Version     : V1.0, 2012-06-08
 Copyright   : marunomaruno
 Description : 日付を扱うユーティリティ(公開用)
 ============================================================================
 */
#ifndef DATEUTIL_H_
#define DATEUTIL_H_

enum {
    YEAR_LENGTH = 4,
    MONTH_LENGTH = 2,
    DAY_LENGTH = 2,
};

/**
 * システム時刻を曜日(日、月、...、土)文字列に変換する。
 * @param systemTime システム時刻
 * @param weekString 曜日を表す文字列を格納する文字列へのポインター
 * @return 曜日を表す文字列
 */
char* toJaWeekString(char *weekString, time_t systemTime);

/**
 * year年がうるう年か平年かを返す。
 * @param year 西暦年。正数を指定する。
 * @return うるう年のとき1、平年のとき0
 */
int isLeap(int year);

/**
 * year年month月の最後の日付を返す。
 * @param year 西暦年
 * @param month 月。ただし、通常の月より1引いた値を使う(0~11)
 * @return year年month月の最後の日付
 */
int lastMonthDay(int year, int month);

/**
 * 日付文字列をシステム時刻に変換する。
 * 日付は、西暦年が1900以上とするが、厳密に月・日の範囲内でなければ不正な日付と
する。
 * @param dateString 日付を表す文字列("YYYYMMDD")
 * @return システム時刻(1970年1月1日 0時0分0秒からの経過時間(秒単位))。変換でき
ない場合、-1.
 */
time_t toStrictSystemTime(char* dateString);

/**
 * 日付文字列をシステム時刻に変換する。
 * 日付は、西暦年が1901以上、月は1~12の範囲、日は1~31の範囲内でなければ不正な日
付とする。
 * @param dateString 日付を表す文字列("YYYYMMDD")
 * @return システム時刻(1970年1月1日 0時0分0秒からの経過時間(秒単位))。変換でき
ない場合、-1.
 */
time_t toSystemTime(char *dateString);

/**
 * システム時刻を日付文字列に変換する。
 * @param systemTime システム時刻
 * @param dateString 日付を表す文字列を格納する文字列へのポインター
 * @return 日付を表す文字列("YYYYMMDD")
 */
char* toDateString(char *dateString, time_t systemTime);

#endif /* DATEUTIL_H_ */
----


▲ 非公開用ヘッダー

内部的に使うだけの関数の定義。
リトルエンディアンを意識するのはここだけ。

□ DateUtilInner.h
---
/*
 ============================================================================
 Name        : DateUtilInner.h
 Author      : marunomaruno
 Version     : V1.0, 2012-06-08
 Copyright   : marunomaruno
 Description : 日付を扱うユーティリティ(非公開用)
 ============================================================================
 */
#ifndef DATE_UTIL_INNER_H_
#define DATE_UTIL_INNER_H_

static struct tm* makeTMStruct(char* weekString, struct tm* workTime);

#endif /* DATE_UTIL_INNER_H_ */
---


▲ モジュール

□ DateUtil.c
---
/*
 ============================================================================
 Name        : DateUtil.c
 Author      : marunomaruno
 Version     : V1.0, 2012-06-08
 Copyright   : marunomaruno
 Description : 日付を扱うユーティリティ
 ============================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>

#include "DateUtil.h"
#include "DateUtilInner.h"

/**
 * 日付文字列をシステム時刻に変換する。
 * 日付は、西暦年が1900以上とするが、厳密に月・日の範囲内でなければ不正な日付と
する。
 * @param dateString 日付を表す文字列("YYYYMMDD")
 * @return システム時刻(1970年1月1日 0時0分0秒からの経過時間(秒単位))。変換でき
ない場合、-1.
 */
time_t toStrictSystemTime(char* dateString) {
    struct tm workTime;

    if (strlen(dateString) != (YEAR_LENGTH + MONTH_LENGTH + DAY_LENGTH)) {
        return -1;
    }

    if (makeTMStruct(dateString, &workTime) == NULL) {
        return -1;
    }

    if (workTime.tm_mday > lastMonthDay(workTime.tm_year, workTime.tm_mon)) {
        return -1;
    }

    return (mktime(&workTime));
}

/**
 * 日付文字列をシステム時刻に変換する。
 * 日付は、西暦年が1901以上、月は1~12の範囲、日は1~31の範囲内でなければ不正な日
付とする。
 * @param dateString 日付を表す文字列("YYYYMMDD")
 * @return システム時刻(1970年1月1日 0時0分0秒からの経過時間(秒単位))。変換でき
ない場合、-1.
 */
time_t toSystemTime(char* dateString) {
    struct tm workTime;
    if (makeTMStruct(dateString, &workTime) == NULL) {
        return -1;
    }
    return (mktime(&workTime));
}

struct tm* makeTMStruct(char* weekString, struct tm* workTime) {
    char year[YEAR_LENGTH + 1];
    char month[MONTH_LENGTH + 1];
    char day[DAY_LENGTH + 1];

    if (strlen(weekString) != (YEAR_LENGTH + MONTH_LENGTH + DAY_LENGTH)) {
        return NULL;
    }

    // 年を設定する
    strncpy(year, weekString + 0, YEAR_LENGTH);
    year[YEAR_LENGTH] = '¥0';
    workTime->tm_year = atoi(year) - 1900;
    if (workTime->tm_year <= 0) {
        return NULL;
    }

    // 月を設定する
    strncpy(month, weekString + (YEAR_LENGTH), MONTH_LENGTH);
    month[MONTH_LENGTH] = '¥0';
    workTime->tm_mon = atoi(month) - 1;
    if (workTime->tm_mon < 0 || workTime->tm_mon > 11) {
        return NULL;
    }

    // 日を設定する
    strncpy(day, weekString + (YEAR_LENGTH + MONTH_LENGTH), DAY_LENGTH);
    day[DAY_LENGTH] = '¥0';
    workTime->tm_mday = atoi(day);
    if (workTime->tm_mday < 1 || workTime->tm_mday > 31) {
        return NULL;
    }

    // 時刻を設定する
    workTime->tm_hour = 0;
    workTime->tm_min = 0;
    workTime->tm_sec = 0;
    workTime->tm_isdst = -1;

    return workTime;
}

/**
 * システム時刻を日付文字列に変換する。
 * @param systemTime システム時刻
 * @param dateString 日付を表す文字列を格納する文字列へのポインター
 * @return 日付を表す文字列("YYYYMMDD")
 */
char* toDateString(char *dateString, time_t systemTime) {
    struct tm* time = localtime(&systemTime);
    strftime(dateString, ((YEAR_LENGTH + MONTH_LENGTH + DAY_LENGTH) + 1),
            "%Y%m%d", time);
    return dateString;
}

/**
 * システム時刻を曜日(日、月、...、土)文字列に変換する。
 * @param systemTime システム時刻
 * @param weekString 曜日を表す文字列を格納する文字列へのポインター
 * @return 曜日を表す文字列
 */
char* toJaWeekString(char *weekString, time_t systemTime) {
    const char WEEK[][3] = { "日", "月", "火", "水", "木", "金", "土", "日", };
    struct tm* time = localtime(&systemTime);
    strncpy(weekString, WEEK[time->tm_wday], 2);
    weekString[2] = '¥0';
    return weekString;
}

/**
 * year年がうるう年か平年かを返す。
 * @param year 西暦年。正数を指定する。
 * @return うるう年のとき1、平年のとき0
 */
int isLeap(int year) {
    assert(year > 0);
    return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0));
}

/**
 * year年month月の最後の日付を返す。
 * @param year 西暦年
 * @param month 月。ただし、通常の月より1引いた値を使う(0~11)
 * @return year年month月の最後の日付
 */
int lastMonthDay(int year, int month) {
    const int LAST_DAYS[][2] = { { 31, 31 }, // 1
            { 28, 29 }, // 2
            { 31, 31 }, // 3
            { 30, 30 }, // 4
            { 31, 31 }, // 5
            { 30, 30 }, // 6
            { 31, 31 }, // 7
            { 31, 31 }, // 8
            { 30, 30 }, // 9
            { 31, 31 }, // 10
            { 30, 30 }, // 11
            { 31, 31 }, // 12
            };

    return LAST_DAYS[month][isLeap(year)];
}
---


▲ テスト

上記の関数を確認するためのテスト・プログラム。
数字、ひらがな、かたかなの限界値をチェックする。
また、リトルエンディアン前提なので、バイト順が逆転している場合に範囲になるかどう
かもチェックする。


□ DateUtilTest.c
---
/*
 ============================================================================
 Name        : DateUtilTest.c
 Author      : marunomaruno
 Version     : V1.0, 2012-06-08
 Copyright   : marunomaruno
 Description : 日付を扱うユーティリティのテスト
 ============================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>

#include "DateUtil.h"

int main(void) {
    time_t calendarTime;
    char buffer[100];

    printf("test start¥n");
    fflush(stdout);

    // isLeap()
    assert(isLeap(2000));
    assert(isLeap(2012));
    assert(!isLeap(2013));
    assert(!isLeap(2100));

    // lastMonthDay()
    assert(31 == lastMonthDay(2012, 0));
    assert(29 == lastMonthDay(2012, 1));
    assert(31 == lastMonthDay(2012, 2));
    assert(30 == lastMonthDay(2012, 3));
    assert(31 == lastMonthDay(2012, 4));
    assert(30 == lastMonthDay(2012, 5));
    assert(31 == lastMonthDay(2012, 6));
    assert(31 == lastMonthDay(2012, 7));
    assert(30 == lastMonthDay(2012, 8));
    assert(31 == lastMonthDay(2012, 9));
    assert(30 == lastMonthDay(2012, 10));
    assert(31 == lastMonthDay(2012, 11));

    assert(31 == lastMonthDay(2013, 0));
    assert(28 == lastMonthDay(2013, 1));
    assert(31 == lastMonthDay(2013, 2));
    assert(30 == lastMonthDay(2013, 3));
    assert(31 == lastMonthDay(2013, 4));
    assert(30 == lastMonthDay(2013, 5));
    assert(31 == lastMonthDay(2013, 6));
    assert(31 == lastMonthDay(2013, 7));
    assert(30 == lastMonthDay(2013, 8));
    assert(31 == lastMonthDay(2013, 9));
    assert(30 == lastMonthDay(2013, 10));
    assert(31 == lastMonthDay(2013, 11));

    // 本日
    printf("%s¥n", toDateString(buffer, time(NULL)));
    printf("%s¥n", toJaWeekString(buffer, time(NULL)));

    // toCalendarTime(), toStrictCalendarTime(), toDateString(), toJaWeekString
()
    // 1. 平年
    strcpy(buffer, "20100228");
    calendarTime = toSystemTime(buffer);
    assert(strcmp("20100228", toDateString(buffer, calendarTime)) == 0);
    assert(strcmp("日", toJaWeekString(buffer, calendarTime)) == 0);

    // 2. 平年(厳密にはエラー)
    strcpy(buffer, "20100229");
    calendarTime = toSystemTime(buffer);
    assert(strcmp("20100301", toDateString(buffer, calendarTime)) == 0);
    assert(strcmp("月", toJaWeekString(buffer, calendarTime)) == 0);

    // 3. 平年
    strcpy(buffer, "20100228");
    calendarTime = toStrictSystemTime(buffer);
    assert(strcmp("20100228", toDateString(buffer, calendarTime)) == 0);
    assert(strcmp("日", toJaWeekString(buffer, calendarTime)) == 0);

    // 4. 平年(エラー)
    strcpy(buffer, "20100229");
    calendarTime = toStrictSystemTime(buffer);
    assert(calendarTime == -1);

    // 5. うるう年
    strcpy(buffer, "20120229");
    calendarTime = toSystemTime(buffer);
    assert(strcmp("20120229", toDateString(buffer, calendarTime)) == 0);
    assert(strcmp("水", toJaWeekString(buffer, calendarTime)) == 0);

    // 6. うるう年(厳密にはエラー)
    strcpy(buffer, "20120230");
    calendarTime = toSystemTime(buffer);
    assert(strcmp("20120301", toDateString(buffer, calendarTime)) == 0);
    assert(strcmp("木", toJaWeekString(buffer, calendarTime)) == 0);

    // 7. うるう年
    strcpy(buffer, "20120229");
    calendarTime = toStrictSystemTime(buffer);
    assert(strcmp("20120229", toDateString(buffer, calendarTime)) == 0);
    assert(strcmp("水", toJaWeekString(buffer, calendarTime)) == 0);

    // 8. 平うるう年(エラー)
    strcpy(buffer, "20120230");
    calendarTime = toStrictSystemTime(buffer);
    assert(calendarTime == -1);

    // 9. 日付不正(1900年)
    strcpy(buffer, "19000101");
    calendarTime = toSystemTime(buffer);
    assert(calendarTime == -1);
    calendarTime = toStrictSystemTime(buffer);
    assert(calendarTime == -1);

    // 10. 日付不正(0月)
    strcpy(buffer, "20000010");
    calendarTime = toSystemTime(buffer);
    assert(calendarTime == -1);
    calendarTime = toStrictSystemTime(buffer);
    assert(calendarTime == -1);

    // 11. 日付不正(32日)
    strcpy(buffer, "20120532");
    calendarTime = toSystemTime(buffer);
    assert(calendarTime == -1);
    calendarTime = toStrictSystemTime(buffer);
    assert(calendarTime == -1);

    // 12. 日付不正(9文字)
    strcpy(buffer, "201205301");
    calendarTime = toSystemTime(buffer);
    assert(calendarTime == -1);
    calendarTime = toStrictSystemTime(buffer);
    assert(calendarTime == -1);

    // 13. 日付不正(7文字)
    strcpy(buffer, "2012053");
    calendarTime = toSystemTime(buffer);
    assert(calendarTime == -1);
    calendarTime = toStrictSystemTime(buffer);
    assert(calendarTime == -1);

    printf("test end¥n");
    fflush(stdout);

    return 0;
}
---

                                                                            以上


最新の画像もっと見る

コメントを投稿