/* * expose_newlib.c * Pheonix * * Created by Steven Abner on 10/8/11. * Copyright 2011 __MyCompanyName__. All rights reserved. * */ #include #include #include extern int printf(const char *restrict, ...); extern void newlib_tzset(void); #define TZSET() newlib_tzset() extern time_t newlib_mktime(struct tm *tmPtr); extern struct tm *newlib_localtime_r(const time_t *timer, struct tm *tmPtr); #define MKTIME newlib_mktime #define LCTIME newlib_localtime_r typedef struct __tzrule_struct { char ch; int m; int n; int d; int s; time_t change; long offset; /* Match type of _timezone. */ } __tzrule_type; typedef struct __tzinfo_struct { int __tznorth; int __tzyear; __tzrule_type __tzrule[2]; } __tzinfo_type; extern __tzinfo_type *__gettzinfo(void); static void load_70base(struct tm *tmPtr) { tmPtr->tm_sec = 0; tmPtr->tm_min = 0; tmPtr->tm_hour = 0; tmPtr->tm_mday = 1; tmPtr->tm_mon = 0; tmPtr->tm_year = 1970 - 1900; tmPtr->tm_wday = 0; tmPtr->tm_yday = 0; tmPtr->tm_isdst = -1; } static struct { int y0, y1; char *sfStr, *tzStr; } sftests[ ] = { 536544000, 978393600, "FKT4FKST,M9.2.6/24:00:00,M4.3.6/24:00:00", "FKT4FKST,M9.2.6/24:00:00,M4.3.6/24:00:00", 820540800, 1325376000, "GMT+00BST-1,M3.5.0/1:00:00,M10.5.0/2:00:00", "GMT+00BST-1,M3.5.0/1:00:00,M10.5.0/2:00:00", 473472000, 631238400, "MSK-3MSD-4,M3.5.0/2:00:00,M9.5.0/3:00:00", "MSK-3MSD-4,M3.5.0/2:00:00,M9.5.0/3:00:00", 820540800, 1325376000, "EET-2EEST,M3.5.0,M10.5.0/3", "EET-2EEST,M3.5.0,M10.5.0/3", 631238400, 820540800, "LHST-10:30:00LHST-11:00:00,M10.5.0,M3.1.0", "LHST-10:30:00LHST-11:00:00,M10.5.0,M3.1.0", 315619200, 662774400, "CKT10CKHST9:30,M10.5.0/0,M3.1.0/0", "CKT10CKHST9:30,M10.5.0/0,M3.1.0/0", 536544000, 1167696000, "PST8PDT,M4.1.0,M10.5.0", "PST8PDT,M4.1.0,M10.5.0", 86400, 1325376000, "EST+3EDT+2,M10.1.0/0,M2.3.0/0", "EST+03EDT,M10.1.0/00:00:00,M2.3.0/00:00:00", //must start these after Jan 1st midnight (else newlib considers out of limits) 18000, 31553999, "EST5EDT,M4.5.0/2,M10.5.0/2", "EST5EDT,M4.5.0/2,M10.5.0/2", 21600, 31557599, "CST6CDT,M4.5.0/2,M10.5.0/2", "CST6CDT,M4.5.0/2,M10.5.0/2", 25200, 31561199, "MST7MDT,M4.5.0/2,M10.5.0/2", "MST7MDT,M4.5.0/2,M10.5.0/2", 28800, 31564799, "PST8PDT,M4.5.0/2,M10.5.0/2", "PST8PDT,M4.5.0/2,M10.5.0/2", 32400, 31568399, "YST9YDT,M4.5.0/2,M10.5.0/2", "YST9YDT,M4.5.0/2,M10.5.0/2", 36000, 31571999, "AHST10AHDT,M4.5.0/2,M10.5.0/2", "AHST10AHDT,M4.5.0/2,M10.5.0/2", 39600, 31575599, "BST11BDT,M4.5.0/2,M10.5.0/2", "BST11BDT,M4.5.0/2,M10.5.0/2", 12600, 31548599, "NST3:30NDT,M4.5.0/2,M10.5.0/2", "NST3:30NDT,M4.5.0/2,M10.5.0/2", 14400, 31550399, "AST4ADT,M4.5.0/2,M10.5.0/2", "AST4ADT,M4.5.0/2,M10.5.0/2", 18000, 31553999, "CST5CDT,M4.5.0/0,M10.5.0/0", "CST5CDT,M4.5.0/0,M10.5.0/0", 21600, 31557599, "CST6CDT,M4.5.0/2,M10.5.0/3", "CST6CDT,M4.5.0/2,M10.5.0/3", 18000, 31519799, "EST5EHDT4:30,M10.5.0/0,J52/0", "EST5EHDT4:30,M10.5.0/0,J52/0", 14400, 31525199, "CLT4CLST,M10.2.6/24,J88/0", "CLT4CLST,M10.2.6/24,J88/0", 25200, 31557599, "EAST7EASST,M10.2.6/21,J87/21", "EAST7EASST,M10.2.6/21,J87/21", //since I use cy0 also as local must increase these start points for newlib 3600, 31532399, "CET-1CEST,J151/0,M9.5.0/0", "CET-1CEST,J151/0,M9.5.0/0", 7200, 31528799, "EET-2EEST,M5.1.6/24,M10.1.6/24", "EET-2EEST,M5.1.6/24,M10.1.6/24", 28800, 31507199, "HKT-8HKST,M4.3.6/27:30,M10.3.6/27:30", "HKT-8HKST,M4.3.6/27:30,M10.3.6/27:30", 7200, 31528799, "EET-2EEST,J121/1,J274/3", "EET-2EEST,J121/1,J274/3", 7200, 31528799, "CAT-2CAST,J121/0,J288/0", "CAT-2CAST,J121/0,J288/0", 39600, 31496399, "EST-10EST,M10.5.0/2,M3.2.0/3", "EST-10EST,M10.5.0/2,M3.2.0/3" }; static void standard_format(void) { int i; struct tm xmt, xlt; time_t t0; for (i = 0; i < ((int) (sizeof (sftests) / sizeof (sftests[0]))); i++) { time_t cy0 = sftests[i].y0; setenv("TZ", sftests[i].sfStr, 1); printf("\"%s\", \"%s\"\n", sftests[i].sfStr, sftests[i].tzStr); TZSET(); for (; cy0 < sftests[i].y1; cy0 += 900) { // test here varies from "ignore and set" below by checking time // also note that the below one can be working on a different time // due to this claims cy0 is UTC, below uses it as local LCTIME(&cy0, &xlt); memmove(&xmt, &xlt, (sizeof(int) * 9)); t0 = MKTIME(&xmt); //just compare the POSIX 9 on all, use exact sizeof() values, either gcc or mac issues otherwise if ((memcmp(&xmt, &xlt, (sizeof(int) * 9)))) printf("mktime not the inverse of localtime(20) %d %s", (int)cy0, asctime(&xmt)); if (t0 != (int)cy0) printf("difference time (20.5) %d %s", (int)cy0, asctime(&xmt)); load_70base(&xmt); // declare cy0 as local time xmt.tm_sec = cy0; t0 = MKTIME(&xmt); //create broken-time from our returned UTC time LCTIME(&t0, &xlt); // check if mktime returned the correct UTC by comparing broken-time stuctures if ((memcmp(&xmt, &xlt, (sizeof(int) * 9)))) { if ((xmt.tm_isdst == -1) && (!memcmp(&xmt, &xlt, (sizeof(int) * 8)))) { printf("newlib feature %d %s", (int)cy0, asctime(&xmt)); } else { printf("difference (21) %d %s", (int)cy0, asctime(&xmt)); } } else { // test the ignore and set ability xlt.tm_yday = (xlt.tm_wday = 0); // re-use the local broken-time from localtime() t0 = MKTIME(&xlt); // xmt left alone for broken-time comparisons if ((memcmp(&xmt, &xlt, (sizeof(int) * 9)))) printf("difference (22) %d\n", (int)cy0); // mktime with incorrect guess // xlt from last mktime() assumed passed, else screwed! __tzinfo_type *tz = __gettzinfo(); int amount_dst = (int)(tz->__tzrule[0].offset - tz->__tzrule[1].offset); if (!xlt.tm_isdst) { xlt.tm_sec += amount_dst; xlt.tm_isdst = 1; } else { xlt.tm_sec -= amount_dst; xlt.tm_isdst = 0; } t0 = MKTIME(&xlt); if ((memcmp(&xmt, &xlt, (sizeof(int) * 9)))) { if ((xmt.tm_isdst == -1) && (!memcmp(&xmt, &xlt, (sizeof(int) * 8)))) { printf("newlib feature %d %s", (int)cy0, asctime(&xmt)); } else { printf("difference (23) %d %s", (int)cy0, asctime(&xmt)); } } } } } } static char buf[80]; static char *zone_name = "GMT0BST,J91/0,J274/0"; static int base_gmtoff = 0; //static char *zone_name = "MSK-3MSD,J91/0,J274/0"; //static int base_gmtoff = 10800; int main(void) { int local_time, flag0 = 0, flag1 = 0; setenv("TZ", zone_name, 1); TZSET(); printf("%19s%30s\n", "MKTIME(LCTIME)", "LCTIME(MKTIME)"); memset(buf, ' ', sizeof(buf)); //trap around change dates for (local_time = ((90 * 86400) - 10800); local_time < ((90 * 86400) + 10800); local_time += 900) { struct tm nlt, nmt; // choose utc as UTC(zone)... consider DST as local phenomenon int utc_time = local_time - base_gmtoff; if (flag0 != 0) buf[25] = ' '; if (flag1 != 0) buf[55] = ' ', buf[56] = ' '; flag0 = (flag1 = 0); // use localtime() to create struct, input utc LCTIME((time_t *)&utc_time, &nlt); // run back throu mktime unaltered, struct in utc + local MKTIME(&nlt); // let's see it strftime(buf, (size_t)26, "%a %b %e %H:%M:%S %Y", &nlt); buf[24] = ' '; // check for newlib feature if (nlt.tm_isdst == -1) buf[(flag0 = 25)] = '1'; // NOTE: using local_time as input, so different conversion // load Jan 1st 1970 load_70base(&nmt); // use local since mktime takes local(definition) // using tm_isdst == -1, since we are in local, we just don't know if STD or DST nmt.tm_sec = local_time; // allow mktime to decide what time or input was time_t ret_time = MKTIME(&nmt); // get localtime to parse what mktime decided, we know localtime works! LCTIME(&ret_time, &nlt); // let's see it strftime(&buf[30], (size_t)26, "%a %b %e %H:%M:%S %Y", &nlt); // check for newlib feature if (nmt.tm_isdst == -1) buf[54] = ' ', buf[(flag1 = 55)] = '1', buf[56] = 0; // can depend on user definition ??? if (ret_time != utc_time) { if (!flag1) buf[54] = ' ', buf[(flag1 = 55)] = '2', buf[56] = 0; else buf[(flag1 = 56)] = '2', buf[57] = 0; } printf("%s%12d\n", buf, ret_time); } printf("\n"); //trap around change dates for (local_time = ((273 * 86400) - 10800); local_time < ((273 * 86400) + 10800); local_time += 900) { struct tm nlt, nmt; int utc_time = local_time - base_gmtoff; if (flag0 != 0) buf[25] = ' '; if (flag1 != 0) buf[55] = ' '; flag0 = (flag1 = 0); // use local to create struct LCTIME((time_t *)&utc_time, &nlt); // run back throu mktime unaltered (inverse, without reguard to return value exactness) MKTIME(&nlt); // let's see it strftime(buf, (size_t)26, "%a %b %e %H:%M:%S %Y", &nlt); buf[24] = ' '; // check for newlib feature if (nlt.tm_isdst == -1) buf[(flag0 = 25)] = '1'; // load Jan 1st 1970 load_70base(&nmt); // set to local (mktime input definition) nmt.tm_sec = local_time; // allow mktime to decide time_t ret_time = MKTIME(&nmt); // get broken-down time from a reliable source // if struct same, then mktime interprets local_time as localtime LCTIME(&ret_time, &nlt); // let's see it strftime(&buf[30], (size_t)26, "%a %b %e %H:%M:%S %Y", &nlt); // check for newlib feature if (nmt.tm_isdst == -1) buf[54] = ' ', buf[(flag1 = 55)] = '1', buf[56] = 0; // can depend on user definition ??? if (ret_time != utc_time) { if (!flag1) buf[54] = ' ', buf[(flag1 = 55)] = '2', buf[56] = 0; else buf[(flag1 = 56)] = '2', buf[57] = 0; } printf("%s%12d\n", buf, ret_time); } printf("\n"); standard_format(); return 0; }