1 /* $NetBSD: cdf_time.c,v 1.6 2014/06/13 02:08:06 christos Exp $ */ 2 /*- 3 * Copyright (c) 2008 Christos Zoulas 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "file.h" 29 30 #ifndef lint 31 #if 0 32 FILE_RCSID("@(#)$File: cdf_time.c,v 1.15 2014/05/14 23:15:42 christos Exp $") 33 #else 34 __RCSID("$NetBSD: cdf_time.c,v 1.6 2014/06/13 02:08:06 christos Exp $"); 35 #endif 36 #endif 37 38 #include <time.h> 39 #ifdef TEST 40 #include <err.h> 41 #endif 42 #include <string.h> 43 44 #include "cdf.h" 45 46 #define isleap(y) ((((y) % 4) == 0) && \ 47 ((((y) % 100) != 0) || (((y) % 400) == 0))) 48 49 static const int mdays[] = { 50 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 51 }; 52 53 /* 54 * Return the number of days between jan 01 1601 and jan 01 of year. 55 */ 56 static int 57 cdf_getdays(int year) 58 { 59 int days = 0; 60 int y; 61 62 for (y = CDF_BASE_YEAR; y < year; y++) 63 days += isleap(y) + 365; 64 65 return days; 66 } 67 68 /* 69 * Return the day within the month 70 */ 71 static int 72 cdf_getday(int year, int days) 73 { 74 size_t m; 75 76 for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) { 77 int sub = mdays[m] + (m == 1 && isleap(year)); 78 if (days < sub) 79 return days; 80 days -= sub; 81 } 82 return days; 83 } 84 85 /* 86 * Return the 0...11 month number. 87 */ 88 static int 89 cdf_getmonth(int year, int days) 90 { 91 size_t m; 92 93 for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) { 94 days -= mdays[m]; 95 if (m == 1 && isleap(year)) 96 days--; 97 if (days <= 0) 98 return (int)m; 99 } 100 return (int)m; 101 } 102 103 int 104 cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t) 105 { 106 struct tm tm; 107 #ifdef HAVE_STRUCT_TM_TM_ZONE 108 static char UTC[] = "UTC"; 109 #endif 110 int rdays; 111 112 /* Unit is 100's of nanoseconds */ 113 ts->tv_nsec = (t % CDF_TIME_PREC) * 100; 114 115 t /= CDF_TIME_PREC; 116 tm.tm_sec = (int)(t % 60); 117 t /= 60; 118 119 tm.tm_min = (int)(t % 60); 120 t /= 60; 121 122 tm.tm_hour = (int)(t % 24); 123 t /= 24; 124 125 /* XXX: Approx */ 126 tm.tm_year = (int)(CDF_BASE_YEAR + (t / 365)); 127 128 rdays = cdf_getdays(tm.tm_year); 129 t -= rdays - 1; 130 tm.tm_mday = cdf_getday(tm.tm_year, (int)t); 131 tm.tm_mon = cdf_getmonth(tm.tm_year, (int)t); 132 tm.tm_wday = 0; 133 tm.tm_yday = 0; 134 tm.tm_isdst = 0; 135 #ifdef HAVE_STRUCT_TM_TM_GMTOFF 136 tm.tm_gmtoff = 0; 137 #endif 138 #ifdef HAVE_STRUCT_TM_TM_ZONE 139 tm.tm_zone = UTC; 140 #endif 141 tm.tm_year -= 1900; 142 ts->tv_sec = mktime(&tm); 143 if (ts->tv_sec == -1) { 144 errno = EINVAL; 145 return -1; 146 } 147 return 0; 148 } 149 150 int 151 /*ARGSUSED*/ 152 cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts) 153 { 154 #ifndef __lint__ 155 (void)&t; 156 (void)&ts; 157 #endif 158 #ifdef notyet 159 struct tm tm; 160 if (gmtime_r(&ts->ts_sec, &tm) == NULL) { 161 errno = EINVAL; 162 return -1; 163 } 164 *t = (ts->ts_nsec / 100) * CDF_TIME_PREC; 165 *t = tm.tm_sec; 166 *t += tm.tm_min * 60; 167 *t += tm.tm_hour * 60 * 60; 168 *t += tm.tm_mday * 60 * 60 * 24; 169 #endif 170 return 0; 171 } 172 173 char * 174 cdf_ctime(const time_t *sec, char *buf) 175 { 176 char *ptr = ctime_r(sec, buf); 177 if (ptr != NULL) 178 return buf; 179 (void)snprintf(buf, 26, "*Bad* 0x%16.16" INT64_T_FORMAT "x\n", 180 (long long)*sec); 181 return buf; 182 } 183 184 185 #ifdef TEST_TIME 186 int 187 main(int argc, char *argv[]) 188 { 189 struct timespec ts; 190 char buf[25]; 191 static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL; 192 static const char *ref = "Sat Apr 23 01:30:00 1977"; 193 char *p, *q; 194 195 cdf_timestamp_to_timespec(&ts, tst); 196 p = cdf_ctime(&ts.tv_sec, buf); 197 if ((q = strchr(p, '\n')) != NULL) 198 *q = '\0'; 199 if (strcmp(ref, p) != 0) 200 errx(1, "Error date %s != %s\n", ref, p); 201 return 0; 202 } 203 #endif 204