5#include "../include/win_strptime.h"
9static inline struct tm* gmtime_r(
const time_t* timer,
struct tm* buf) {
10 return (gmtime_s(buf, timer) == 0) ? buf : NULL;
13static inline struct tm* localtime_r(
const time_t* timer,
struct tm* buf) {
14 return (localtime_s(buf, timer) == 0) ? buf : NULL;
20static inline bool is_leap_year(
int year) {
22 int actual_year = year + 1900;
23 return (actual_year % 4 == 0 && actual_year % 100 != 0) || (actual_year % 400 == 0);
29static inline int days_in_month(
int month,
int year) {
30 static const int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
31 if (month < 0 || month > 11) {
34 if (month == 1 && is_leap_year(year)) {
43static inline bool is_valid_date(
int day,
int month,
int year) {
44 if (month < 0 || month > 11) {
50 return day <= days_in_month(month, year);
64char* strptime(
const char* buf,
const char* fmt,
struct tm* tm) {
65 if (buf == NULL || fmt == NULL || tm == NULL) {
72 bool has_ampm =
false;
74 bool need_date_validation =
false;
79 if (tm->tm_wday == 0 && tm->tm_yday == 0 && tm->tm_isdst == 0) {
85 if (isspace((
unsigned char)*f)) {
86 while (isspace((
unsigned char)*f)) f++;
87 while (isspace((
unsigned char)*s)) s++;
109 bool has_modifier =
false;
110 if (*f ==
'E' || *f ==
'O') {
120 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1]) || !isdigit((
unsigned char)s[2]) ||
121 !isdigit((
unsigned char)s[3])) {
124 int year = (s[0] -
'0') * 1000 + (s[1] -
'0') * 100 + (s[2] -
'0') * 10 + (s[3] -
'0');
125 tm->tm_year = year - 1900;
131 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
134 int year = (s[0] -
'0') * 10 + (s[1] -
'0');
137 tm->tm_year = century * 100 + year - 1900;
139 tm->tm_year = (year >= 69) ? year : (year + 100);
146 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
149 century = (s[0] -
'0') * 10 + (s[1] -
'0');
155 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
158 int month = (s[0] -
'0') * 10 + (s[1] -
'0');
159 if (month < 1 || month > 12) {
162 tm->tm_mon = month - 1;
163 need_date_validation =
true;
169 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
172 int day = (s[0] -
'0') * 10 + (s[1] -
'0');
173 if (day < 1 || day > 31) {
177 need_date_validation =
true;
184 if (*s ==
' ' || *s ==
'0') {
187 if (!isdigit((
unsigned char)s[0])) {
190 int day = (s[0] -
'0');
192 if (isdigit((
unsigned char)s[0])) {
193 day = day * 10 + (s[0] -
'0');
196 if (day < 1 || day > 31) {
200 need_date_validation =
true;
205 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
208 int hour = (s[0] -
'0') * 10 + (s[1] -
'0');
221 if (!isdigit((
unsigned char)s[0])) {
224 int hour = (s[0] -
'0');
226 if (isdigit((
unsigned char)s[0])) {
227 hour = hour * 10 + (s[0] -
'0');
238 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
241 int hour = (s[0] -
'0') * 10 + (s[1] -
'0');
242 if (hour < 1 || hour > 12) {
254 if (!isdigit((
unsigned char)s[0])) {
257 int hour = (s[0] -
'0');
259 if (isdigit((
unsigned char)s[0])) {
260 hour = hour * 10 + (s[0] -
'0');
263 if (hour < 1 || hour > 12) {
271 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
274 int min = (s[0] -
'0') * 10 + (s[1] -
'0');
284 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1])) {
287 int sec = (s[0] -
'0') * 10 + (s[1] -
'0');
297 if ((s[0] ==
'A' || s[0] ==
'a') && (s[1] ==
'M' || s[1] ==
'm')) {
301 }
else if ((s[0] ==
'P' || s[0] ==
'p') && (s[1] ==
'M' || s[1] ==
'm')) {
312 char* result = strptime(s,
"%I:%M:%S %p", tm);
313 if (result == NULL) {
322 char* result = strptime(s,
"%H:%M", tm);
323 if (result == NULL) {
331 char* result = strptime(s,
"%H:%M:%S", tm);
332 if (result == NULL) {
340 char* result = strptime(s,
"%m/%d/%y", tm);
341 if (result == NULL) {
349 char* result = strptime(s,
"%Y-%m-%d", tm);
350 if (result == NULL) {
360 static const char* months[] = {
"january",
"february",
"march",
"april",
"may",
"june",
361 "july",
"august",
"september",
"october",
"november",
"december"};
362 static const char* abbr_months[] = {
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
363 "jul",
"aug",
"sep",
"oct",
"nov",
"dec"};
367 for (
int i = 0; i < 12; i++) {
368 const char* full = months[i];
369 const char* abbr = abbr_months[i];
370 size_t full_len = strlen(full);
375 if (_strnicmp(s, full, full_len) == 0) {
382 if (_strnicmp(s, abbr, abbr_len) == 0) {
393 need_date_validation =
true;
399 static const char* weekdays[] = {
"sunday",
"monday",
"tuesday",
"wednesday",
400 "thursday",
"friday",
"saturday"};
401 static const char* abbr_weekdays[] = {
"sun",
"mon",
"tue",
"wed",
"thu",
"fri",
"sat"};
404 for (
int i = 0; i < 7; i++) {
405 const char* full = weekdays[i];
406 const char* abbr = abbr_weekdays[i];
407 size_t full_len = strlen(full);
411 if (_strnicmp(s, full, full_len) == 0) {
418 if (_strnicmp(s, abbr, abbr_len) == 0) {
433 if (!isdigit((
unsigned char)s[0]) || !isdigit((
unsigned char)s[1]) || !isdigit((
unsigned char)s[2])) {
436 int yday = (s[0] -
'0') * 100 + (s[1] -
'0') * 10 + (s[2] -
'0');
437 if (yday < 1 || yday > 366) {
440 tm->tm_yday = yday - 1;
446 if (!isdigit((
unsigned char)s[0])) {
449 int wday = s[0] -
'0';
450 if (wday < 1 || wday > 7) {
453 tm->tm_wday = (wday == 7) ? 0 : wday;
459 if (!isdigit((
unsigned char)s[0])) {
462 int wday = s[0] -
'0';
474 if (*s ==
'+' || *s ==
'-') {
477 if (isdigit((
unsigned char)s[0]) && isdigit((
unsigned char)s[1])) {
487 if (isdigit((
unsigned char)s[0]) && isdigit((
unsigned char)s[1])) {
492 }
else if (*s ==
'Z' || *s ==
'z') {
502 while (*s !=
'\0' && !isspace((
unsigned char)*s) && *s !=
'+' && *s !=
'-' &&
503 isalpha((
unsigned char)*s)) {
515 if (!isspace((
unsigned char)*s)) {
518 while (isspace((
unsigned char)*s)) {
542 if (is_pm && tm->tm_hour < 12) {
544 }
else if (!is_pm && tm->tm_hour == 12) {
550 if (need_date_validation && !is_valid_date(tm->tm_mday, tm->tm_mon, tm->tm_year)) {
555 if (tm->tm_isdst == 0) {