xref: /netbsd-src/external/bsd/file/dist/src/cdf_time.c (revision ddb176824c39fb0db5ceef3e9e40dcaa273aec38)
1*ddb17682Schristos /*	$NetBSD: cdf_time.c,v 1.12 2023/08/18 19:00:11 christos Exp $	*/
2fa9ee498Schristos 
31b108b8bSchristos /*-
41b108b8bSchristos  * Copyright (c) 2008 Christos Zoulas
51b108b8bSchristos  * All rights reserved.
61b108b8bSchristos  *
71b108b8bSchristos  * Redistribution and use in source and binary forms, with or without
81b108b8bSchristos  * modification, are permitted provided that the following conditions
91b108b8bSchristos  * are met:
101b108b8bSchristos  * 1. Redistributions of source code must retain the above copyright
111b108b8bSchristos  *    notice, this list of conditions and the following disclaimer.
121b108b8bSchristos  * 2. Redistributions in binary form must reproduce the above copyright
131b108b8bSchristos  *    notice, this list of conditions and the following disclaimer in the
141b108b8bSchristos  *    documentation and/or other materials provided with the distribution.
151b108b8bSchristos  *
161b108b8bSchristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
171b108b8bSchristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
181b108b8bSchristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
191b108b8bSchristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
201b108b8bSchristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211b108b8bSchristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221b108b8bSchristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231b108b8bSchristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241b108b8bSchristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251b108b8bSchristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261b108b8bSchristos  * POSSIBILITY OF SUCH DAMAGE.
271b108b8bSchristos  */
281b108b8bSchristos 
291b108b8bSchristos #include "file.h"
301b108b8bSchristos 
311b108b8bSchristos #ifndef lint
321b108b8bSchristos #if 0
33*ddb17682Schristos FILE_RCSID("@(#)$File: cdf_time.c,v 1.24 2023/07/17 15:54:44 christos Exp $")
341b108b8bSchristos #else
35*ddb17682Schristos __RCSID("$NetBSD: cdf_time.c,v 1.12 2023/08/18 19:00:11 christos Exp $");
361b108b8bSchristos #endif
371b108b8bSchristos #endif
381b108b8bSchristos 
391b108b8bSchristos #include <time.h>
401b108b8bSchristos #ifdef TEST
411b108b8bSchristos #include <err.h>
421b108b8bSchristos #endif
431b108b8bSchristos #include <string.h>
441b108b8bSchristos 
451b108b8bSchristos #include "cdf.h"
461b108b8bSchristos 
471b108b8bSchristos #define isleap(y) ((((y) % 4) == 0) && \
481b108b8bSchristos     ((((y) % 100) != 0) || (((y) % 400) == 0)))
491b108b8bSchristos 
501b108b8bSchristos static const int mdays[] = {
511b108b8bSchristos     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
521b108b8bSchristos };
531b108b8bSchristos 
541b108b8bSchristos /*
551b108b8bSchristos  * Return the number of days between jan 01 1601 and jan 01 of year.
561b108b8bSchristos  */
571b108b8bSchristos static int
cdf_getdays(int year)581b108b8bSchristos cdf_getdays(int year)
591b108b8bSchristos {
601b108b8bSchristos 	int days = 0;
611b108b8bSchristos 	int y;
621b108b8bSchristos 
631b108b8bSchristos 	for (y = CDF_BASE_YEAR; y < year; y++)
641b108b8bSchristos 		days += isleap(y) + 365;
651b108b8bSchristos 
661b108b8bSchristos 	return days;
671b108b8bSchristos }
681b108b8bSchristos 
691b108b8bSchristos /*
701b108b8bSchristos  * Return the day within the month
711b108b8bSchristos  */
721b108b8bSchristos static int
cdf_getday(int year,int days)731b108b8bSchristos cdf_getday(int year, int days)
741b108b8bSchristos {
751b108b8bSchristos 	size_t m;
761b108b8bSchristos 
77d0c65b7bSchristos 	for (m = 0; m < __arraycount(mdays); m++) {
781b108b8bSchristos 		int sub = mdays[m] + (m == 1 && isleap(year));
791b108b8bSchristos 		if (days < sub)
801b108b8bSchristos 			return days;
811b108b8bSchristos 		days -= sub;
821b108b8bSchristos 	}
831b108b8bSchristos 	return days;
841b108b8bSchristos }
851b108b8bSchristos 
861b108b8bSchristos /*
871b108b8bSchristos  * Return the 0...11 month number.
881b108b8bSchristos  */
891b108b8bSchristos static int
cdf_getmonth(int year,int days)901b108b8bSchristos cdf_getmonth(int year, int days)
911b108b8bSchristos {
921b108b8bSchristos 	size_t m;
931b108b8bSchristos 
94d0c65b7bSchristos 	for (m = 0; m < __arraycount(mdays); m++) {
951b108b8bSchristos 		days -= mdays[m];
961b108b8bSchristos 		if (m == 1 && isleap(year))
971b108b8bSchristos 			days--;
981b108b8bSchristos 		if (days <= 0)
99d0c65b7bSchristos 			return CAST(int, m);
1001b108b8bSchristos 	}
101d0c65b7bSchristos 	return CAST(int, m);
1021b108b8bSchristos }
1031b108b8bSchristos 
1041b108b8bSchristos int
cdf_timestamp_to_timespec(struct timespec * ts,cdf_timestamp_t t)1051b108b8bSchristos cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t)
1061b108b8bSchristos {
1071b108b8bSchristos 	struct tm tm;
1081b108b8bSchristos #ifdef HAVE_STRUCT_TM_TM_ZONE
1091b108b8bSchristos 	static char UTC[] = "UTC";
1101b108b8bSchristos #endif
1111b108b8bSchristos 	int rdays;
1121b108b8bSchristos 
1131b108b8bSchristos 	/* Unit is 100's of nanoseconds */
1141b108b8bSchristos 	ts->tv_nsec = (t % CDF_TIME_PREC) * 100;
1151b108b8bSchristos 
1161b108b8bSchristos 	t /= CDF_TIME_PREC;
117d0c65b7bSchristos 	tm.tm_sec = CAST(int, t % 60);
1181b108b8bSchristos 	t /= 60;
1191b108b8bSchristos 
120d0c65b7bSchristos 	tm.tm_min = CAST(int, t % 60);
1211b108b8bSchristos 	t /= 60;
1221b108b8bSchristos 
123d0c65b7bSchristos 	tm.tm_hour = CAST(int, t % 24);
1241b108b8bSchristos 	t /= 24;
1251b108b8bSchristos 
126819e6405Schristos 	/* XXX: Approx */
127d0c65b7bSchristos 	tm.tm_year = CAST(int, CDF_BASE_YEAR + (t / 365));
1281b108b8bSchristos 
1291b108b8bSchristos 	rdays = cdf_getdays(tm.tm_year);
130046a38ddSchristos 	t -= rdays - 1;
131d0c65b7bSchristos 	tm.tm_mday = cdf_getday(tm.tm_year, CAST(int, t));
132d0c65b7bSchristos 	tm.tm_mon = cdf_getmonth(tm.tm_year, CAST(int, t));
1331b108b8bSchristos 	tm.tm_wday = 0;
1341b108b8bSchristos 	tm.tm_yday = 0;
1351b108b8bSchristos 	tm.tm_isdst = 0;
1361b108b8bSchristos #ifdef HAVE_STRUCT_TM_TM_GMTOFF
1371b108b8bSchristos 	tm.tm_gmtoff = 0;
1381b108b8bSchristos #endif
1391b108b8bSchristos #ifdef HAVE_STRUCT_TM_TM_ZONE
1401b108b8bSchristos 	tm.tm_zone = UTC;
1411b108b8bSchristos #endif
1421b108b8bSchristos 	tm.tm_year -= 1900;
1431b108b8bSchristos 	ts->tv_sec = mktime(&tm);
1441b108b8bSchristos 	if (ts->tv_sec == -1) {
1451b108b8bSchristos 		errno = EINVAL;
1461b108b8bSchristos 		return -1;
1471b108b8bSchristos 	}
1481b108b8bSchristos 	return 0;
1491b108b8bSchristos }
1501b108b8bSchristos 
1511b108b8bSchristos int
1527c25ef23Schristos /*ARGSUSED*/
cdf_timespec_to_timestamp(cdf_timestamp_t * t,const struct timespec * ts)1531b108b8bSchristos cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts)
1541b108b8bSchristos {
1557c25ef23Schristos #ifndef __lint__
1561b108b8bSchristos 	(void)&t;
1571b108b8bSchristos 	(void)&ts;
1587c25ef23Schristos #endif
1591b108b8bSchristos #ifdef notyet
1601b108b8bSchristos 	struct tm tm;
1611b108b8bSchristos 	if (gmtime_r(&ts->ts_sec, &tm) == NULL) {
1621b108b8bSchristos 		errno = EINVAL;
1631b108b8bSchristos 		return -1;
1641b108b8bSchristos 	}
1651b108b8bSchristos 	*t = (ts->ts_nsec / 100) * CDF_TIME_PREC;
1661d4cb158Schristos 	*t += tm.tm_sec;
1671b108b8bSchristos 	*t += tm.tm_min * 60;
1681b108b8bSchristos 	*t += tm.tm_hour * 60 * 60;
1691b108b8bSchristos 	*t += tm.tm_mday * 60 * 60 * 24;
1701b108b8bSchristos #endif
1711b108b8bSchristos 	return 0;
1721b108b8bSchristos }
1731b108b8bSchristos 
1742344ff98Schristos char *
cdf_ctime(const time_t * sec,char * buf)17520d96732Schristos cdf_ctime(const time_t *sec, char *buf)
1762344ff98Schristos {
177*ddb17682Schristos 	char *ptr = *sec > MAX_CTIME ? NULL : ctime_r(sec, buf);
1782344ff98Schristos 	if (ptr != NULL)
17920d96732Schristos 		return buf;
1801d4cb158Schristos #ifdef WIN32
1811d4cb158Schristos 	(void)snprintf(buf, 26, "*Bad* 0x%16.16I64x\n",
1821d4cb158Schristos 	    CAST(long long, *sec));
1831d4cb158Schristos #else
184e2725312Schristos 	(void)snprintf(buf, 26, "*Bad* %#16.16" INT64_T_FORMAT "x\n",
185d0c65b7bSchristos 	    CAST(long long, *sec));
1861d4cb158Schristos #endif
18720d96732Schristos 	return buf;
1882344ff98Schristos }
1892344ff98Schristos 
1901b108b8bSchristos 
191819e6405Schristos #ifdef TEST_TIME
1921b108b8bSchristos int
main(int argc,char * argv[])1931b108b8bSchristos main(int argc, char *argv[])
1941b108b8bSchristos {
1951b108b8bSchristos 	struct timespec ts;
19620d96732Schristos 	char buf[25];
1971b108b8bSchristos 	static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL;
1981b108b8bSchristos 	static const char *ref = "Sat Apr 23 01:30:00 1977";
1991b108b8bSchristos 	char *p, *q;
2001b108b8bSchristos 
2011b108b8bSchristos 	cdf_timestamp_to_timespec(&ts, tst);
20220d96732Schristos 	p = cdf_ctime(&ts.tv_sec, buf);
2031b108b8bSchristos 	if ((q = strchr(p, '\n')) != NULL)
2041b108b8bSchristos 		*q = '\0';
2051b108b8bSchristos 	if (strcmp(ref, p) != 0)
2061b108b8bSchristos 		errx(1, "Error date %s != %s\n", ref, p);
2071b108b8bSchristos 	return 0;
2081b108b8bSchristos }
2091b108b8bSchristos #endif
210