1191739Sobrien/*- 2191739Sobrien * Copyright (c) 2008 Christos Zoulas 3191739Sobrien * All rights reserved. 4191739Sobrien * 5191739Sobrien * Redistribution and use in source and binary forms, with or without 6191739Sobrien * modification, are permitted provided that the following conditions 7191739Sobrien * are met: 8191739Sobrien * 1. Redistributions of source code must retain the above copyright 9191739Sobrien * notice, this list of conditions and the following disclaimer. 10191739Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11191739Sobrien * notice, this list of conditions and the following disclaimer in the 12191739Sobrien * documentation and/or other materials provided with the distribution. 13191739Sobrien * 14191739Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 15191739Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16191739Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17191739Sobrien * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18191739Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19191739Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20191739Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21191739Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22191739Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23191739Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24191739Sobrien * POSSIBILITY OF SUCH DAMAGE. 25191739Sobrien */ 26191739Sobrien 27191739Sobrien#include "file.h" 28191739Sobrien 29191739Sobrien#ifndef lint 30328875SeadlerFILE_RCSID("@(#)$File: cdf_time.c,v 1.16 2017/03/29 15:57:48 christos Exp $") 31191739Sobrien#endif 32191739Sobrien 33191739Sobrien#include <time.h> 34191739Sobrien#ifdef TEST 35191739Sobrien#include <err.h> 36191739Sobrien#endif 37191739Sobrien#include <string.h> 38191739Sobrien 39191739Sobrien#include "cdf.h" 40191739Sobrien 41191739Sobrien#define isleap(y) ((((y) % 4) == 0) && \ 42191739Sobrien ((((y) % 100) != 0) || (((y) % 400) == 0))) 43191739Sobrien 44191739Sobrienstatic const int mdays[] = { 45191739Sobrien 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 46191739Sobrien}; 47191739Sobrien 48191739Sobrien/* 49191739Sobrien * Return the number of days between jan 01 1601 and jan 01 of year. 50191739Sobrien */ 51191739Sobrienstatic int 52191739Sobriencdf_getdays(int year) 53191739Sobrien{ 54191739Sobrien int days = 0; 55191739Sobrien int y; 56191739Sobrien 57191739Sobrien for (y = CDF_BASE_YEAR; y < year; y++) 58191739Sobrien days += isleap(y) + 365; 59191739Sobrien 60191739Sobrien return days; 61191739Sobrien} 62191739Sobrien 63191739Sobrien/* 64191739Sobrien * Return the day within the month 65191739Sobrien */ 66191739Sobrienstatic int 67191739Sobriencdf_getday(int year, int days) 68191739Sobrien{ 69191739Sobrien size_t m; 70191739Sobrien 71191739Sobrien for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) { 72191739Sobrien int sub = mdays[m] + (m == 1 && isleap(year)); 73191739Sobrien if (days < sub) 74191739Sobrien return days; 75191739Sobrien days -= sub; 76191739Sobrien } 77191739Sobrien return days; 78191739Sobrien} 79191739Sobrien 80191739Sobrien/* 81191739Sobrien * Return the 0...11 month number. 82191739Sobrien */ 83191739Sobrienstatic int 84191739Sobriencdf_getmonth(int year, int days) 85191739Sobrien{ 86191739Sobrien size_t m; 87191739Sobrien 88191739Sobrien for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) { 89191739Sobrien days -= mdays[m]; 90191739Sobrien if (m == 1 && isleap(year)) 91191739Sobrien days--; 92191739Sobrien if (days <= 0) 93191739Sobrien return (int)m; 94191739Sobrien } 95191739Sobrien return (int)m; 96191739Sobrien} 97191739Sobrien 98191739Sobrienint 99191739Sobriencdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t) 100191739Sobrien{ 101191739Sobrien struct tm tm; 102191739Sobrien#ifdef HAVE_STRUCT_TM_TM_ZONE 103191739Sobrien static char UTC[] = "UTC"; 104191739Sobrien#endif 105192348Sdelphij int rdays; 106191739Sobrien 107191739Sobrien /* Unit is 100's of nanoseconds */ 108191739Sobrien ts->tv_nsec = (t % CDF_TIME_PREC) * 100; 109191739Sobrien 110191739Sobrien t /= CDF_TIME_PREC; 111226048Sobrien tm.tm_sec = (int)(t % 60); 112191739Sobrien t /= 60; 113191739Sobrien 114226048Sobrien tm.tm_min = (int)(t % 60); 115191739Sobrien t /= 60; 116191739Sobrien 117226048Sobrien tm.tm_hour = (int)(t % 24); 118191739Sobrien t /= 24; 119191739Sobrien 120267843Sdelphij /* XXX: Approx */ 121226048Sobrien tm.tm_year = (int)(CDF_BASE_YEAR + (t / 365)); 122191739Sobrien 123192348Sdelphij rdays = cdf_getdays(tm.tm_year); 124234250Sobrien t -= rdays - 1; 125226048Sobrien tm.tm_mday = cdf_getday(tm.tm_year, (int)t); 126226048Sobrien tm.tm_mon = cdf_getmonth(tm.tm_year, (int)t); 127191739Sobrien tm.tm_wday = 0; 128191739Sobrien tm.tm_yday = 0; 129191739Sobrien tm.tm_isdst = 0; 130191739Sobrien#ifdef HAVE_STRUCT_TM_TM_GMTOFF 131191739Sobrien tm.tm_gmtoff = 0; 132191739Sobrien#endif 133191739Sobrien#ifdef HAVE_STRUCT_TM_TM_ZONE 134191739Sobrien tm.tm_zone = UTC; 135191739Sobrien#endif 136191739Sobrien tm.tm_year -= 1900; 137191739Sobrien ts->tv_sec = mktime(&tm); 138191739Sobrien if (ts->tv_sec == -1) { 139191739Sobrien errno = EINVAL; 140191739Sobrien return -1; 141191739Sobrien } 142191739Sobrien return 0; 143191739Sobrien} 144191739Sobrien 145191739Sobrienint 146226048Sobrien/*ARGSUSED*/ 147191739Sobriencdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts) 148191739Sobrien{ 149226048Sobrien#ifndef __lint__ 150191739Sobrien (void)&t; 151191739Sobrien (void)&ts; 152226048Sobrien#endif 153191739Sobrien#ifdef notyet 154191739Sobrien struct tm tm; 155191739Sobrien if (gmtime_r(&ts->ts_sec, &tm) == NULL) { 156191739Sobrien errno = EINVAL; 157191739Sobrien return -1; 158191739Sobrien } 159191739Sobrien *t = (ts->ts_nsec / 100) * CDF_TIME_PREC; 160191739Sobrien *t = tm.tm_sec; 161191739Sobrien *t += tm.tm_min * 60; 162191739Sobrien *t += tm.tm_hour * 60 * 60; 163191739Sobrien *t += tm.tm_mday * 60 * 60 * 24; 164191739Sobrien#endif 165191739Sobrien return 0; 166191739Sobrien} 167191739Sobrien 168226048Sobrienchar * 169267843Sdelphijcdf_ctime(const time_t *sec, char *buf) 170226048Sobrien{ 171267843Sdelphij char *ptr = ctime_r(sec, buf); 172226048Sobrien if (ptr != NULL) 173267843Sdelphij return buf; 174328875Seadler (void)snprintf(buf, 26, "*Bad* %#16.16" INT64_T_FORMAT "x\n", 175226048Sobrien (long long)*sec); 176267843Sdelphij return buf; 177226048Sobrien} 178191739Sobrien 179226048Sobrien 180267843Sdelphij#ifdef TEST_TIME 181191739Sobrienint 182191739Sobrienmain(int argc, char *argv[]) 183191739Sobrien{ 184191739Sobrien struct timespec ts; 185267843Sdelphij char buf[25]; 186191739Sobrien static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL; 187191739Sobrien static const char *ref = "Sat Apr 23 01:30:00 1977"; 188191739Sobrien char *p, *q; 189191739Sobrien 190191739Sobrien cdf_timestamp_to_timespec(&ts, tst); 191267843Sdelphij p = cdf_ctime(&ts.tv_sec, buf); 192191739Sobrien if ((q = strchr(p, '\n')) != NULL) 193191739Sobrien *q = '\0'; 194191739Sobrien if (strcmp(ref, p) != 0) 195191739Sobrien errx(1, "Error date %s != %s\n", ref, p); 196191739Sobrien return 0; 197191739Sobrien} 198191739Sobrien#endif 199