こんにちは、もがちゃんです。
今回は、C言語で日時を出力する際にフォーマットして出力したい場合に使えるstrftimeの使い方を簡単なサンプルプログラムとともに説明します。
目次
strftimeの構文
#include <time.h>
size_t strftime(char* restrict s,
size_t maxsize,
const char* restrict format,
const struct tm* restrict timeptr);
strftimeの説明
strftimeは、timeptrポインタが指す日付時間情報をformatポインタが指す書式に編集した結果の文字列をsで指定されたポインタが指す領域に格納します。
sで指定されたポインタが指す領域のバイトサイズは、maxsizeで指定します。
strftime関数は、formatが指す文字列による制御に従って、sが指す配列に文字を格納する。その書式は、初期シフト状態で始まり、初期シフト状態で終わる多バイト文字の並びでなければならない。format文字列は、0個以上の変換指定子と通常の多バイト文字から成る。変換指定子は、%文字で始まり、その後に、次に規定する省略可能な修飾文字E又はOが続く。さらに、変換指定子の動作を決定する文字が続く。すべての通常の多バイト文字(終端ナル文字を含む。)は、変換せずに配列にコピーする。領域の重なり合うオブジェクト間でコピーが行われるとき、その動作は、未定義とする。maxsize個を超える文字を、配列に格納することはない。
JISX3010 プログラム言語C
日付時間情報をフォーマットした結果の文字列を格納する領域の先頭ポインタを指定します。
sで指定したポインタが指す領域のサイズを指定します。
日付時間情報を編集する際に使用するフォーマット文字列の先頭ポインタを指定します。
フォーマットして出力したい日付時間情報を指すポインタを指定します。
編集結果の終端文字(’\0’)を含む文字列のサイズが
maxsize以下の場合、sに格納した文字列のサイズを返します。
それ以外の場合、0を返します。
変換指定子 | 意味 |
---|---|
%a | ロケールの簡略化された曜日の名前に置き換わる。[tm_wday] |
%A | ロケールの簡略化されていない曜日の名前に置き換わる。[tm_wday] |
%b | ロケールの簡略化された月の名前に置き換わる。[tm_mon] |
%B | ロケールの簡略化されていない月の名前に置き換わる。[tm_mon] |
%c | ロケールの適切な日付及び時刻表現に置き換わる。 |
%C | 西暦の年を100で除算し整数に切り捨てた10進数(00~99)に置き換わる。[tm_year] |
%d | 10進数で月の日(01~31)に置き換わる。[tm_mday] |
%D | ”%m/%d/%y”と等価な日付表現に置き換わる。[tm_mon,tm_mday,tm_year] |
%e | 10進数で月の日(1~31)に置き換わる。1けたの数の場合,空白文字を前置する。[tm_mday] |
%F | “%Y-%m-%d”(JIS X 0301での日付形式)と等価な日付表現に置き換わる。[tm_year,tm_mon,tm_mday] |
%g | 暦週に基づく年の下2けたを表す10進数(00~99)に置き換わる。[tm_year,tm_wday,tm_yday] |
%G | 暦週に基づく年を表す10進数(例えば1997)に置き換わる。[tm_year,tm_wday,tm_yday] |
%h | “%b”と等価な表現に置き換わる。[tm_mon] |
%H | (24時間制)時間を表す10進数(00~23)に置き換わる。[tm_hour] |
%I | (12時間制)時間を表す10進数(01~12)に置き換わる。[tm_hour] |
%j | 10進数で年の日(001~366)に置き換わる。[tm_yday] |
%m | 10進数で月(01~12)に置き換わる。[tm_mon] |
%M | 10進数で分(00~59)に置き換わる。[tm_min] |
%n | 改行文字に置き換わる。 |
%p | ロケールの,12時間制に関連した午前又は午後の表記に相当するものに置き換わる。[tm_hour] |
%r | ロケールの12時間制での時刻表現に置き換わる。[tm_hour,tm_min,tm_sec] |
%R | “%H:%M”と等価な時刻表現に置き換わる。[tm_hour,tm_min] |
%S | 10進数で秒(00~60)に置き換わる。[tm_sec] |
%t | 水平タブ文字に置き換わる。 |
%T | “%H:%M:%S”(JIS X 0301での時刻形式)に等価な時刻表現に置き換わる。[tm_hour,tm_min,tm_sec] |
%u | JIS X 0301が規定する暦週の中の日の序数を表す10進数(1~7)に置き換わる。このとき,月曜日は1とする。[tm_wday] |
%U | 10進数で(最初の日曜日を第1週の最初の日とした)年の週の数(00~53)に置き換わる。[tm_year,tm_wday,tm_yday] |
%V | JIS X 0301が規定する暦週の序数を表す10進数(01~53)に置き換わる。[tm_year,tm_wday,tm_yday] |
%w | 10進数で曜日(0~6)に置き換わる。このとき,日曜日を0とする。[tm_wday] |
%W | 10進数で(最初の月曜日を第1週の最初の日とした)年の週番号(00~53)に置き換わる。[tm_year,tm_wday,tm_yday] |
%x | ロケールの適切な日付表現に置き換わる。 |
%X | ロケールの適切な時刻表現に置き換わる。 |
%y | 10進数で西暦の下2けたの年(00~99)に置き換わる。[tm_year] |
%Y | 10進数で西暦の年(例えば,1997)に置き換わる。[tm_year] |
%z | UTCからの時差をJIS X 0301が規定する形式で表したものに置き換わる。 時間帯が不明な場合,どのような文字とも置き換わらない。[tm_isdst] |
%Z | 時間帯の名前又は略号に置き換わる。時間帯が不明な場合,どのような文字とも置き換わらない。[tm_isdst] |
%% | %に置き換わる。 |
%Ec | ロケールでの日付及び時刻の代替表現に置き換わる。 |
%EC | ロケールでの代替表現である年号に置き換わる。 |
%Ex | ロケールでの日付の代替表現に置き換わる。 |
%EX | ロケールでの時刻の代替表現に置き換わる。 |
%Ey | ロケールでの代替表現である%EC(年号)に対応した年に置き換わる。 |
%EY | ロケールでの年の完全形式の代替表現に置き換わる。 |
%Od | ロケールでの代替数値記号を使った日の表現に置き換わる(必要に応じて0を前置する。 0に対応する代替数値記号が存在しない場合,空白文字を前置する。)。 |
%Oe | ロケールでの代替数値記号を使った日の表現に置き換わる(必要に応じて空白文字を前置する。)。 |
%OH | ロケールでの代替数値記号を使った時間(24時間制)の表現に置き換わる。 |
%OI | ロケールでの代替数値記号を使った時間(12時間制)の表現に置き換わる。 |
%Om | ロケールでの代替数値記号を使った月の表現に置き換わる。 |
%OM | ロケールでの代替数値記号を使った分の表現に置き換わる。 |
%OS | ロケールでの代替数値記号を使った秒の表現に置き換わる。 |
%Ou | ロケールでの代替表現によるJIS X 0301が規定する暦週の中の序数に置き換わる。このとき,月曜日は1とする。 |
%OU | ロケールでの代替数値記号を使った週番号の表現に置き換わる。 |
%OV | ロケールでの代替数値記号を使ったJIS X 0301が規定する暦週の序数の表現に置き換わる。 |
%Ow | ロケールでの代替数値記号を使った曜日の表現に置き換わる。 |
%OW | ロケールでの代替数値記号を使った年の週番号の表現に置き換わる。 |
%Oy | ロケールでの代替数値記号を使った西暦の下2けたの年に置き換わる。 |
%g,%G 及び%V | JIS X 0301が規定する暦週に基づく年に対応する値を与える。 |
変換指定子 | 意味 |
---|---|
%a | %Aの最初の3文字 |
%A | “Sunday”,“Monday”,“Tuesday”,“Wednesday”,“Thursday”,“Friday”,又は“Saturday”のいずれか一つの文字列 |
%b | %Bの最初の3文字 |
%B | “January”,“February”,“March”,“April”,“May”,“June”,“July”,“August”,“September”,“October”,“November”,又は“December”のいずれか一つの文字列 |
%c | “%a %b %e %T %Y”と等価な文字列 |
%p | “AM”,“PM”のいずれか一方の文字列 |
%r | “%I:%M:%S %p”と等価な文字列 |
%x | “%m/%d/%y”と等価な文字列 |
%X | %Tと等価な文字列 |
%Z | 処理系定義の文字列 |
strftimeの使い方サンプル
strftimeを使って日付時間情報をフォーマットして出力する簡単なサンプルプログラムとその実行結果を紹介します。
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void) {
//timer == NULL指定時
time_t timer = time(NULL);
if (timer == -1) {
fprintf(stdout, "time error\n");
return -1;
}
struct tm *tm = localtime(&timer);
if (tm == NULL) {
fprintf(stdout, "localtime error\n");
return -1;
}
char small_buff[8];
char large_buff[256];
memset(small_buff, '#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void) {
//timer == NULL指定時
time_t timer = time(NULL);
if (timer == -1) {
fprintf(stdout, "time error\n");
return -1;
}
struct tm *tm = localtime(&timer);
if (tm == NULL) {
fprintf(stdout, "localtime error\n");
return -1;
}
char small_buff[8];
char large_buff[256];
memset(small_buff, '\0', sizeof(small_buff));
memset(large_buff, '\0', sizeof(large_buff));
/* 結果がmaxsize:8を超過する場合 */
fprintf(stdout, "strftime(small_buff):%d\n",
(int)strftime(small_buff, sizeof(small_buff), "%Y/%m/%d", tm));
fprintf(stdout, "small_buff:[%s]\n", small_buff);
/* 結果がmaxsize:256以下となる場合 */
fprintf(stdout, "strftime(large_buff):%d\n",
(int)strftime(large_buff, sizeof(large_buff),
"%Y/%m/%d(%A) %H:%M:%S",
tm));
fprintf(stdout, "large_buff:[%s]\n", large_buff);
}
', sizeof(small_buff));
memset(large_buff, '#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void) {
//timer == NULL指定時
time_t timer = time(NULL);
if (timer == -1) {
fprintf(stdout, "time error\n");
return -1;
}
struct tm *tm = localtime(&timer);
if (tm == NULL) {
fprintf(stdout, "localtime error\n");
return -1;
}
char small_buff[8];
char large_buff[256];
memset(small_buff, '\0', sizeof(small_buff));
memset(large_buff, '\0', sizeof(large_buff));
/* 結果がmaxsize:8を超過する場合 */
fprintf(stdout, "strftime(small_buff):%d\n",
(int)strftime(small_buff, sizeof(small_buff), "%Y/%m/%d", tm));
fprintf(stdout, "small_buff:[%s]\n", small_buff);
/* 結果がmaxsize:256以下となる場合 */
fprintf(stdout, "strftime(large_buff):%d\n",
(int)strftime(large_buff, sizeof(large_buff),
"%Y/%m/%d(%A) %H:%M:%S",
tm));
fprintf(stdout, "large_buff:[%s]\n", large_buff);
}
', sizeof(large_buff));
/* 結果がmaxsize:8を超過する場合 */
fprintf(stdout, "strftime(small_buff):%d\n",
(int)strftime(small_buff, sizeof(small_buff), "%Y/%m/%d", tm));
fprintf(stdout, "small_buff:[%s]\n", small_buff);
/* 結果がmaxsize:256以下となる場合 */
fprintf(stdout, "strftime(large_buff):%d\n",
(int)strftime(large_buff, sizeof(large_buff),
"%Y/%m/%d(%A) %H:%M:%S",
tm));
fprintf(stdout, "large_buff:[%s]\n", large_buff);
}
実行結果では、small_buffに途中まで結果が格納されていますが、windowsのeclipse上で実行した場合は、結果は設定されていませんでした。
JIS規格で規定されている正しい動作としては、strftimeの戻り値が0になる場合は、結果が出力されないのが正しい動作のはず
strftimeの使い方まとめ
- sで指定する編集結果を格納するための領域は十分なサイズの領域を準備しておく必要がある。
- maxsizeには、sで指定した領域のサイズを指定する。
- strftimeを使用する場合、期待した結果を得るには正しいロケールを設定する必要がある。