[공통] util → framework 유틸 (ACM-CM-002)

This commit is contained in:
forge-bot 2026-07-18 11:09:11 +00:00
parent 2557011197
commit 3cb3b83120

View file

@ -1,135 +1,52 @@
/*
* util_date.c - / (plain C)
*/
#include "acq_util.h"
#include <string.h>
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> #include <time.h>
static int is_all_digit(const char *s, int len) #define DATE_BUF_SIZE 32
{
int i; typedef struct {
for (i = 0; i < len; i++) { int year;
if (!isdigit((unsigned char)s[i])) int month;
return 0; int day;
} } date_t;
return 1;
int date_parse(const char* str, date_t* out) {
if (!str || !out) return -1;
return sscanf(str, "%4d-%2d-%2d", &out->year, &out->month, &out->day);
} }
static int to_int(const char *s, int len) int date_format(const date_t* d, char* buf, size_t len) {
{ if (!d || !buf) return -1;
int i, v = 0; return snprintf(buf, len, "%04d-%02d-%02d", d->year, d->month, d->day);
for (i = 0; i < len; i++)
v = v * 10 + (s[i] - '0');
return v;
} }
static int days_in_month(int y, int m) int date_diff_days(const date_t* from, const date_t* to) {
{ if (!from || !to) return 0;
static const int d[] = { 31, 28, 31, 30, 31, 30, struct tm a = {0}, b = {0};
31, 31, 30, 31, 30, 31 }; a.tm_year = from->year - 1900; a.tm_mon = from->month - 1; a.tm_mday = from->day;
if (m < 1 || m > 12) b.tm_year = to->year - 1900; b.tm_mon = to->month - 1; b.tm_mday = to->day;
return 0; return (int)(difftime(mktime(&b), mktime(&a)) / 86400);
if (m == 2) {
int leap = (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
return leap ? 29 : 28;
}
return d[m - 1];
} }
int date_is_valid(const char *yyyymmdd) int date_add_days(const date_t* d, int days, date_t* out) {
{ if (!d || !out) return -1;
int y, m, d; struct tm base = {0};
base.tm_year = d->year - 1900; base.tm_mon = d->month - 1; base.tm_mday = d->day;
if (!yyyymmdd || strlen(yyyymmdd) < 8) base.tm_mday += days;
return 0; mktime(&base);
if (!is_all_digit(yyyymmdd, 8)) out->year = base.tm_year + 1900;
return 0; out->month = base.tm_mon + 1;
out->day = base.tm_mday;
y = to_int(yyyymmdd, 4);
m = to_int(yyyymmdd + 4, 2);
d = to_int(yyyymmdd + 6, 2);
if (y < 1900 || y > 2999)
return 0;
if (m < 1 || m > 12)
return 0;
if (d < 1 || d > days_in_month(y, m))
return 0;
return 1;
}
/* Sakamoto 알고리즘: 0=일요일 ... 6=토요일 */
int date_weekday(const char *yyyymmdd)
{
static const int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
int y, m, d;
if (!date_is_valid(yyyymmdd))
return -1;
y = to_int(yyyymmdd, 4);
m = to_int(yyyymmdd + 4, 2);
d = to_int(yyyymmdd + 6, 2);
if (m < 3)
y -= 1;
return (y + y / 4 - y / 100 + y / 400 + t[m - 1] + d) % 7;
}
int date_is_weekend(const char *yyyymmdd)
{
int w = date_weekday(yyyymmdd);
return (w == 0 || w == 6) ? 1 : 0;
}
/* YYYYMMDD 를 하루 증가시킨다 (in==out 허용) */
static void add_one_day(const char *in, char *out)
{
int y = to_int(in, 4);
int m = to_int(in + 4, 2);
int d = to_int(in + 6, 2);
d++;
if (d > days_in_month(y, m)) {
d = 1;
m++;
if (m > 12) {
m = 1;
y++;
}
}
snprintf(out, 9, "%04d%02d%02d", y, m, d);
}
int date_next_business(const char *yyyymmdd, char *out)
{
char cur[9];
int guard = 0;
if (!date_is_valid(yyyymmdd) || !out)
return -1;
memcpy(cur, yyyymmdd, 8);
cur[8] = '\0';
do {
add_one_day(cur, cur);
if (++guard > 14) /* 무한루프 방지 */
return -1;
} while (date_is_weekend(cur));
memcpy(out, cur, 8);
out[8] = '\0';
return 0; return 0;
} }
void date_today(char *out) int date_today(date_t* out) {
{ if (!out) return -1;
time_t now = time(NULL); time_t now = time(NULL);
struct tm tmv; struct tm* t = localtime(&now);
localtime_r(&now, &tmv); out->year = t->tm_year + 1900;
strftime(out, 9, "%Y%m%d", &tmv); out->month = t->tm_mon + 1;
out->day = t->tm_mday;
return 0;
} }