PHOTON_COMMON_EXPORT struct tm * localtime_r( const time_t * timep, struct tm * tm ) { localsub(timep, 0L, tm); return tm; }
struct tm * localtime_r(const time_t * const timep, struct tm *p_tm) { _RWLOCK_RDLOCK(&lcl_rwlock); tzset_basic(1); localsub(timep, 0L, p_tm); _RWLOCK_UNLOCK(&lcl_rwlock); return(p_tm); }
struct tm * localtime(const time_t * const timep) { static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_key_t localtime_key = -1; struct tm *p_tm; if (__isthreaded != 0) { if (localtime_key < 0) { _pthread_mutex_lock(&localtime_mutex); if (localtime_key < 0) { if (_pthread_key_create(&localtime_key, free) < 0) { _pthread_mutex_unlock(&localtime_mutex); return(NULL); } } _pthread_mutex_unlock(&localtime_mutex); } p_tm = _pthread_getspecific(localtime_key); if (p_tm == NULL) { if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) return(NULL); _pthread_setspecific(localtime_key, p_tm); } _RWLOCK_RDLOCK(&lcl_rwlock); tzset_basic(1); localsub(timep, 0L, p_tm); _RWLOCK_UNLOCK(&lcl_rwlock); return(p_tm); } else { tzset_basic(0); localsub(timep, 0L, &tm); return(&tm); } }
/* data is here so we can use this as a callback for IPC */ static int timezone_get_time(const char *timezone, struct tm *tm, double *diff, void *data) { time_t now; struct tm *tm_tmp; #ifdef PRIVATE_TZLIB struct state *tzinfo = timezone_load(timezone); if(!tzinfo) return -1; time(&now); localsub(&now, 0, tm, tzinfo); free(tzinfo); #else const gchar *old_tz; /* Store the current TZ value. */ old_tz = g_getenv("TZ"); g_setenv("TZ", timezone, TRUE); time(&now); tm_tmp = localtime(&now); *tm = *tm_tmp; /* Must copy, localtime uses local buffer */ /* Reset the old TZ value. */ if (old_tz == NULL) g_unsetenv("TZ"); else g_setenv("TZ", old_tz, TRUE); #endif /* Calculate user's localtime, and compare. If same, no output */ tm_tmp = localtime(&now); if (tm_tmp->tm_hour == tm->tm_hour && tm_tmp->tm_min == tm->tm_min) return 1; *diff = timezone_calc_difference(tm, tm_tmp); return 0; }
/* * The easy way to behave "as if no library function calls" localtime * is to not call it--so we drop its guts into "localsub", which can be * freely called. (And no, the PANS doesn't require the above behavior-- * but it *is* desirable.) * * The unused offset argument is for the benefit of mktime variants. */ static struct pg_tm * localsub(const pg_time_t *timep, long offset, struct pg_tm * tmp, const pg_tz *tz) { const struct state *sp; const struct ttinfo *ttisp; int i; struct pg_tm *result; const pg_time_t t = *timep; sp = &tz->state; if ((sp->goback && t < sp->ats[0]) || (sp->goahead && t > sp->ats[sp->timecnt - 1])) { pg_time_t newt = t; pg_time_t seconds; pg_time_t tcycles; int64 icycles; if (t < sp->ats[0]) seconds = sp->ats[0] - t; else seconds = t - sp->ats[sp->timecnt - 1]; --seconds; tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; ++tcycles; icycles = tcycles; if (tcycles - icycles >= 1 || icycles - tcycles >= 1) return NULL; seconds = icycles; seconds *= YEARSPERREPEAT; seconds *= AVGSECSPERYEAR; if (t < sp->ats[0]) newt += seconds; else newt -= seconds; if (newt < sp->ats[0] || newt > sp->ats[sp->timecnt - 1]) return NULL; /* "cannot happen" */ result = localsub(&newt, offset, tmp, tz); if (result == tmp) { pg_time_t newy; newy = tmp->tm_year; if (t < sp->ats[0]) newy -= icycles * YEARSPERREPEAT; else newy += icycles * YEARSPERREPEAT; tmp->tm_year = newy; if (tmp->tm_year != newy) return NULL; } return result; } if (sp->timecnt == 0 || t < sp->ats[0]) { i = 0; while (sp->ttis[i].tt_isdst) if (++i >= sp->typecnt) { i = 0; break; } } else { int lo = 1; int hi = sp->timecnt; while (lo < hi) { int mid = (lo + hi) >> 1; if (t < sp->ats[mid]) hi = mid; else lo = mid + 1; } i = (int) sp->types[lo - 1]; } ttisp = &sp->ttis[i]; result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; tmp->tm_zone = &sp->chars[ttisp->tt_abbrind]; return result; }
struct pg_tm * pg_localtime(const pg_time_t *timep, const pg_tz *tz) { return localsub(timep, 0L, &tm, tz); }
struct pg_tm * pg_localtime_r(const pg_time_t *timep, const pg_tz *tz, struct pg_tm* tm) { return localsub(timep, 0L, tm, tz); }
/*ARGSUSED*/ static struct tm * localsub(const time_t * const timep, const long offset __unused, struct tm * const tmp) { struct state * sp; const struct ttinfo * ttisp; int i; struct tm * result; const time_t t = *timep; sp = lclptr; if ((sp->goback && t < sp->ats[0]) || (sp->goahead && t > sp->ats[sp->timecnt - 1])) { time_t newt = t; time_t seconds; time_t tcycles; int_fast64_t icycles; if (t < sp->ats[0]) seconds = sp->ats[0] - t; else seconds = t - sp->ats[sp->timecnt - 1]; --seconds; tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; ++tcycles; icycles = tcycles; if (tcycles - icycles >= 1 || icycles - tcycles >= 1) return NULL; seconds = icycles; seconds *= YEARSPERREPEAT; seconds *= AVGSECSPERYEAR; if (t < sp->ats[0]) newt += seconds; else newt -= seconds; if (newt < sp->ats[0] || newt > sp->ats[sp->timecnt - 1]) return NULL; /* "cannot happen" */ result = localsub(&newt, offset, tmp); if (result == tmp) { time_t newy; newy = tmp->tm_year; if (t < sp->ats[0]) newy -= icycles * YEARSPERREPEAT; else newy += icycles * YEARSPERREPEAT; tmp->tm_year = newy; if (tmp->tm_year != newy) return NULL; } return result; } if (sp->timecnt == 0 || t < sp->ats[0]) { i = 0; while (sp->ttis[i].tt_isdst) if (++i >= sp->typecnt) { i = 0; break; } } else { int lo = 1; int hi = sp->timecnt; while (lo < hi) { int mid = (lo + hi) >> 1; if (t < sp->ats[mid]) hi = mid; else lo = mid + 1; } i = (int) sp->types[lo - 1]; } ttisp = &sp->ttis[i]; /* ** To get (wrong) behavior that's compatible with System V Release 2.0 ** you'd replace the statement below with ** t += ttisp->tt_gmtoff; ** timesub(&t, 0L, sp, tmp); */ result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef TM_ZONE tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; #endif /* defined TM_ZONE */ return result; }