1570af302Sopenharmony_ci// SPDX-License-Identifier: MIT 2570af302Sopenharmony_ci 3570af302Sopenharmony_ci#define _GNU_SOURCE /* For tm_gmtoff */ 4570af302Sopenharmony_ci#include <stddef.h> 5570af302Sopenharmony_ci#include <stdlib.h> 6570af302Sopenharmony_ci#include <string.h> 7570af302Sopenharmony_ci#include <time.h> 8570af302Sopenharmony_ci#include "test.h" 9570af302Sopenharmony_ci 10570af302Sopenharmony_ci/** 11570af302Sopenharmony_ci * checkStrptime - parse time and check if it matches expected value 12570af302Sopenharmony_ci * 13570af302Sopenharmony_ci * This function compares time and date fields of tm structure only. 14570af302Sopenharmony_ci * It's because tm_wday and tm_yday may - but don't have to - be set 15570af302Sopenharmony_ci * while parsing a date. 16570af302Sopenharmony_ci */ 17570af302Sopenharmony_cistatic void checkStrptime(const char *s, const char *format, const struct tm *expected) { 18570af302Sopenharmony_ci struct tm tm = { }; 19570af302Sopenharmony_ci const char *ret; 20570af302Sopenharmony_ci 21570af302Sopenharmony_ci ret = strptime(s, format, &tm); 22570af302Sopenharmony_ci if (!ret || *ret != '\0') { 23570af302Sopenharmony_ci t_error("\"%s\": failed to parse \"%s\"\n", format, s); 24570af302Sopenharmony_ci } else if (tm.tm_sec != expected->tm_sec || 25570af302Sopenharmony_ci tm.tm_min != expected->tm_min || 26570af302Sopenharmony_ci tm.tm_hour != expected->tm_hour || 27570af302Sopenharmony_ci tm.tm_mday != expected->tm_mday || 28570af302Sopenharmony_ci tm.tm_mon != expected->tm_mon || 29570af302Sopenharmony_ci tm.tm_year != expected->tm_year) { 30570af302Sopenharmony_ci char buf1[64]; 31570af302Sopenharmony_ci char buf2[64]; 32570af302Sopenharmony_ci 33570af302Sopenharmony_ci strftime(buf1, sizeof(buf1), "%FT%H:%M:%S%Z", expected); 34570af302Sopenharmony_ci strftime(buf2, sizeof(buf2), "%FT%H:%M:%S%Z", &tm); 35570af302Sopenharmony_ci 36570af302Sopenharmony_ci t_error("\"%s\": for \"%s\" expected %s but got %s\n", format, s, buf1, buf2); 37570af302Sopenharmony_ci } 38570af302Sopenharmony_ci} 39570af302Sopenharmony_ci 40570af302Sopenharmony_cistatic void checkStrptimeTz(const char *s, int h, int m) { 41570af302Sopenharmony_ci long int expected = h * 3600 + m * 60; 42570af302Sopenharmony_ci struct tm tm = { }; 43570af302Sopenharmony_ci const char *ret; 44570af302Sopenharmony_ci 45570af302Sopenharmony_ci ret = strptime(s, "%z", &tm); 46570af302Sopenharmony_ci if (!ret || *ret != '\0') { 47570af302Sopenharmony_ci t_error("\"%%z\": failed to parse \"%s\"\n", s); 48570af302Sopenharmony_ci } else if (tm.tm_gmtoff != expected) { 49570af302Sopenharmony_ci t_error("\"%%z\": for \"%s\" expected tm_gmtoff %ld but got %ld\n", s, tm.tm_gmtoff, expected); 50570af302Sopenharmony_ci } 51570af302Sopenharmony_ci} 52570af302Sopenharmony_ci 53570af302Sopenharmony_cistatic struct tm tm1 = { 54570af302Sopenharmony_ci .tm_sec = 8, 55570af302Sopenharmony_ci .tm_min = 57, 56570af302Sopenharmony_ci .tm_hour = 20, 57570af302Sopenharmony_ci .tm_mday = 0, 58570af302Sopenharmony_ci .tm_mon = 0, 59570af302Sopenharmony_ci .tm_year = 0, 60570af302Sopenharmony_ci}; 61570af302Sopenharmony_ci 62570af302Sopenharmony_cistatic struct tm tm2 = { 63570af302Sopenharmony_ci .tm_sec = 0, 64570af302Sopenharmony_ci .tm_min = 0, 65570af302Sopenharmony_ci .tm_hour = 0, 66570af302Sopenharmony_ci .tm_mday = 25, 67570af302Sopenharmony_ci .tm_mon = 8 - 1, 68570af302Sopenharmony_ci .tm_year = 1991 - 1900, 69570af302Sopenharmony_ci}; 70570af302Sopenharmony_ci 71570af302Sopenharmony_cistatic struct tm tm3 = { 72570af302Sopenharmony_ci .tm_sec = 0, 73570af302Sopenharmony_ci .tm_min = 0, 74570af302Sopenharmony_ci .tm_hour = 0, 75570af302Sopenharmony_ci .tm_mday = 21, 76570af302Sopenharmony_ci .tm_mon = 10 - 1, 77570af302Sopenharmony_ci .tm_year = 2015 - 1900, 78570af302Sopenharmony_ci}; 79570af302Sopenharmony_ci 80570af302Sopenharmony_cistatic struct tm tm4 = { 81570af302Sopenharmony_ci .tm_sec = 0, 82570af302Sopenharmony_ci .tm_min = 0, 83570af302Sopenharmony_ci .tm_hour = 0, 84570af302Sopenharmony_ci .tm_mday = 10, 85570af302Sopenharmony_ci .tm_mon = 7 - 1, 86570af302Sopenharmony_ci .tm_year = 1856 - 1900, 87570af302Sopenharmony_ci}; 88570af302Sopenharmony_ci 89570af302Sopenharmony_ciint main() { 90570af302Sopenharmony_ci setenv("TZ", "UTC0", 1); 91570af302Sopenharmony_ci 92570af302Sopenharmony_ci /* Time */ 93570af302Sopenharmony_ci checkStrptime("20:57:08", "%H:%M:%S", &tm1); 94570af302Sopenharmony_ci checkStrptime("20:57:8", "%R:%S", &tm1); 95570af302Sopenharmony_ci checkStrptime("20:57:08", "%T", &tm1); 96570af302Sopenharmony_ci 97570af302Sopenharmony_ci /* Format */ 98570af302Sopenharmony_ci checkStrptime("20:57:08", "%H : %M : %S", &tm1); 99570af302Sopenharmony_ci checkStrptime("20 57 08", "%H %M %S", &tm1); 100570af302Sopenharmony_ci checkStrptime("20%57%08", "%H %% %M%%%S", &tm1); 101570af302Sopenharmony_ci checkStrptime("foo20bar57qux08 ", "foo %Hbar %M qux%S ", &tm1); 102570af302Sopenharmony_ci 103570af302Sopenharmony_ci /* Date */ 104570af302Sopenharmony_ci checkStrptime("1991-08-25", "%Y-%m-%d", &tm2); 105570af302Sopenharmony_ci checkStrptime("25.08.91", "%d.%m.%y", &tm2); 106570af302Sopenharmony_ci checkStrptime("08/25/91", "%D", &tm2); 107570af302Sopenharmony_ci checkStrptime("21.10.15", "%d.%m.%y", &tm3); 108570af302Sopenharmony_ci checkStrptime("10.7.56 in 18th", "%d.%m.%y in %C th", &tm4); 109570af302Sopenharmony_ci 110570af302Sopenharmony_ci /* Glibc */ 111570af302Sopenharmony_ci checkStrptime("1856-07-10", "%F", &tm4); 112570af302Sopenharmony_ci checkStrptime("683078400", "%s", &tm2); 113570af302Sopenharmony_ci checkStrptimeTz("+0200", 2, 0); 114570af302Sopenharmony_ci checkStrptimeTz("-0530", -5, -30); 115570af302Sopenharmony_ci checkStrptimeTz("-06", -6, 0); 116570af302Sopenharmony_ci 117570af302Sopenharmony_ci return t_status; 118570af302Sopenharmony_ci} 119