xref: /dflybsd-src/contrib/file/src/cdf_time.c (revision 739f0ef867128a933e021db3d831e906fcafd825)
179343712SPeter Avalos /*-
279343712SPeter Avalos  * Copyright (c) 2008 Christos Zoulas
379343712SPeter Avalos  * All rights reserved.
479343712SPeter Avalos  *
579343712SPeter Avalos  * Redistribution and use in source and binary forms, with or without
679343712SPeter Avalos  * modification, are permitted provided that the following conditions
779343712SPeter Avalos  * are met:
879343712SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
979343712SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1079343712SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1179343712SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1279343712SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1379343712SPeter Avalos  *
1479343712SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1579343712SPeter Avalos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1679343712SPeter Avalos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1779343712SPeter Avalos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1879343712SPeter Avalos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1979343712SPeter Avalos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2079343712SPeter Avalos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2179343712SPeter Avalos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2279343712SPeter Avalos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2379343712SPeter Avalos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2479343712SPeter Avalos  * POSSIBILITY OF SUCH DAMAGE.
2579343712SPeter Avalos  */
2679343712SPeter Avalos 
2779343712SPeter Avalos #include "file.h"
2879343712SPeter Avalos 
2979343712SPeter Avalos #ifndef lint
30*3b9cdfa3SAntonio Huete Jimenez FILE_RCSID("@(#)$File: cdf_time.c,v 1.20 2021/12/06 15:33:00 christos Exp $")
3179343712SPeter Avalos #endif
3279343712SPeter Avalos 
3379343712SPeter Avalos #include <time.h>
3479343712SPeter Avalos #ifdef TEST
3579343712SPeter Avalos #include <err.h>
3679343712SPeter Avalos #endif
3779343712SPeter Avalos #include <string.h>
3879343712SPeter Avalos 
3979343712SPeter Avalos #include "cdf.h"
4079343712SPeter Avalos 
4179343712SPeter Avalos #define isleap(y) ((((y) % 4) == 0) && \
4279343712SPeter Avalos     ((((y) % 100) != 0) || (((y) % 400) == 0)))
4379343712SPeter Avalos 
4479343712SPeter Avalos static const int mdays[] = {
4579343712SPeter Avalos     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
4679343712SPeter Avalos };
4779343712SPeter Avalos 
4879343712SPeter Avalos /*
4979343712SPeter Avalos  * Return the number of days between jan 01 1601 and jan 01 of year.
5079343712SPeter Avalos  */
5179343712SPeter Avalos static int
cdf_getdays(int year)5279343712SPeter Avalos cdf_getdays(int year)
5379343712SPeter Avalos {
5479343712SPeter Avalos 	int days = 0;
5579343712SPeter Avalos 	int y;
5679343712SPeter Avalos 
5779343712SPeter Avalos 	for (y = CDF_BASE_YEAR; y < year; y++)
5879343712SPeter Avalos 		days += isleap(y) + 365;
5979343712SPeter Avalos 
6079343712SPeter Avalos 	return days;
6179343712SPeter Avalos }
6279343712SPeter Avalos 
6379343712SPeter Avalos /*
6479343712SPeter Avalos  * Return the day within the month
6579343712SPeter Avalos  */
6679343712SPeter Avalos static int
cdf_getday(int year,int days)6779343712SPeter Avalos cdf_getday(int year, int days)
6879343712SPeter Avalos {
6979343712SPeter Avalos 	size_t m;
7079343712SPeter Avalos 
716fca56fbSSascha Wildner 	for (m = 0; m < __arraycount(mdays); m++) {
7279343712SPeter Avalos 		int sub = mdays[m] + (m == 1 && isleap(year));
7379343712SPeter Avalos 		if (days < sub)
7479343712SPeter Avalos 			return days;
7579343712SPeter Avalos 		days -= sub;
7679343712SPeter Avalos 	}
7779343712SPeter Avalos 	return days;
7879343712SPeter Avalos }
7979343712SPeter Avalos 
8079343712SPeter Avalos /*
8179343712SPeter Avalos  * Return the 0...11 month number.
8279343712SPeter Avalos  */
8379343712SPeter Avalos static int
cdf_getmonth(int year,int days)8479343712SPeter Avalos cdf_getmonth(int year, int days)
8579343712SPeter Avalos {
8679343712SPeter Avalos 	size_t m;
8779343712SPeter Avalos 
886fca56fbSSascha Wildner 	for (m = 0; m < __arraycount(mdays); m++) {
8979343712SPeter Avalos 		days -= mdays[m];
9079343712SPeter Avalos 		if (m == 1 && isleap(year))
9179343712SPeter Avalos 			days--;
9279343712SPeter Avalos 		if (days <= 0)
936fca56fbSSascha Wildner 			return CAST(int, m);
9479343712SPeter Avalos 	}
956fca56fbSSascha Wildner 	return CAST(int, m);
9679343712SPeter Avalos }
9779343712SPeter Avalos 
9879343712SPeter Avalos int
cdf_timestamp_to_timespec(struct timespec * ts,cdf_timestamp_t t)9979343712SPeter Avalos cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t)
10079343712SPeter Avalos {
10179343712SPeter Avalos 	struct tm tm;
10279343712SPeter Avalos #ifdef HAVE_STRUCT_TM_TM_ZONE
10379343712SPeter Avalos 	static char UTC[] = "UTC";
10479343712SPeter Avalos #endif
10579343712SPeter Avalos 	int rdays;
10679343712SPeter Avalos 
10779343712SPeter Avalos 	/* Unit is 100's of nanoseconds */
10879343712SPeter Avalos 	ts->tv_nsec = (t % CDF_TIME_PREC) * 100;
10979343712SPeter Avalos 
11079343712SPeter Avalos 	t /= CDF_TIME_PREC;
1116fca56fbSSascha Wildner 	tm.tm_sec = CAST(int, t % 60);
11279343712SPeter Avalos 	t /= 60;
11379343712SPeter Avalos 
1146fca56fbSSascha Wildner 	tm.tm_min = CAST(int, t % 60);
11579343712SPeter Avalos 	t /= 60;
11679343712SPeter Avalos 
1176fca56fbSSascha Wildner 	tm.tm_hour = CAST(int, t % 24);
11879343712SPeter Avalos 	t /= 24;
11979343712SPeter Avalos 
12082c5fa3eSPeter Avalos 	/* XXX: Approx */
1216fca56fbSSascha Wildner 	tm.tm_year = CAST(int, CDF_BASE_YEAR + (t / 365));
12279343712SPeter Avalos 
12379343712SPeter Avalos 	rdays = cdf_getdays(tm.tm_year);
1249f86ab30SPeter Avalos 	t -= rdays - 1;
1256fca56fbSSascha Wildner 	tm.tm_mday = cdf_getday(tm.tm_year, CAST(int, t));
1266fca56fbSSascha Wildner 	tm.tm_mon = cdf_getmonth(tm.tm_year, CAST(int, t));
12779343712SPeter Avalos 	tm.tm_wday = 0;
12879343712SPeter Avalos 	tm.tm_yday = 0;
12979343712SPeter Avalos 	tm.tm_isdst = 0;
13079343712SPeter Avalos #ifdef HAVE_STRUCT_TM_TM_GMTOFF
13179343712SPeter Avalos 	tm.tm_gmtoff = 0;
13279343712SPeter Avalos #endif
13379343712SPeter Avalos #ifdef HAVE_STRUCT_TM_TM_ZONE
13479343712SPeter Avalos 	tm.tm_zone = UTC;
13579343712SPeter Avalos #endif
13679343712SPeter Avalos 	tm.tm_year -= 1900;
13779343712SPeter Avalos 	ts->tv_sec = mktime(&tm);
13879343712SPeter Avalos 	if (ts->tv_sec == -1) {
13979343712SPeter Avalos 		errno = EINVAL;
14079343712SPeter Avalos 		return -1;
14179343712SPeter Avalos 	}
14279343712SPeter Avalos 	return 0;
14379343712SPeter Avalos }
14479343712SPeter Avalos 
14579343712SPeter Avalos int
146f72f8299SJan Lentfer /*ARGSUSED*/
cdf_timespec_to_timestamp(cdf_timestamp_t * t,const struct timespec * ts)14779343712SPeter Avalos cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts)
14879343712SPeter Avalos {
149f72f8299SJan Lentfer #ifndef __lint__
15079343712SPeter Avalos 	(void)&t;
15179343712SPeter Avalos 	(void)&ts;
152f72f8299SJan Lentfer #endif
15379343712SPeter Avalos #ifdef notyet
15479343712SPeter Avalos 	struct tm tm;
15579343712SPeter Avalos 	if (gmtime_r(&ts->ts_sec, &tm) == NULL) {
15679343712SPeter Avalos 		errno = EINVAL;
15779343712SPeter Avalos 		return -1;
15879343712SPeter Avalos 	}
15979343712SPeter Avalos 	*t = (ts->ts_nsec / 100) * CDF_TIME_PREC;
16079343712SPeter Avalos 	*t = tm.tm_sec;
16179343712SPeter Avalos 	*t += tm.tm_min * 60;
16279343712SPeter Avalos 	*t += tm.tm_hour * 60 * 60;
16379343712SPeter Avalos 	*t += tm.tm_mday * 60 * 60 * 24;
16479343712SPeter Avalos #endif
16579343712SPeter Avalos 	return 0;
16679343712SPeter Avalos }
16779343712SPeter Avalos 
168ff91a668SPeter Avalos char *
cdf_ctime(const time_t * sec,char * buf)169e8af9738SPeter Avalos cdf_ctime(const time_t *sec, char *buf)
170ff91a668SPeter Avalos {
171e8af9738SPeter Avalos 	char *ptr = ctime_r(sec, buf);
172ff91a668SPeter Avalos 	if (ptr != NULL)
173e8af9738SPeter Avalos 		return buf;
174*3b9cdfa3SAntonio Huete Jimenez #ifdef WIN32
175*3b9cdfa3SAntonio Huete Jimenez 	(void)snprintf(buf, 26, "*Bad* 0x%16.16I64x\n",
176*3b9cdfa3SAntonio Huete Jimenez 	    CAST(long long, *sec));
177*3b9cdfa3SAntonio Huete Jimenez #else
178c30bd091SSascha Wildner 	(void)snprintf(buf, 26, "*Bad* %#16.16" INT64_T_FORMAT "x\n",
1796fca56fbSSascha Wildner 	    CAST(long long, *sec));
180*3b9cdfa3SAntonio Huete Jimenez #endif
181e8af9738SPeter Avalos 	return buf;
182ff91a668SPeter Avalos }
183ff91a668SPeter Avalos 
18479343712SPeter Avalos 
185e8af9738SPeter Avalos #ifdef TEST_TIME
18679343712SPeter Avalos int
main(int argc,char * argv[])18779343712SPeter Avalos main(int argc, char *argv[])
18879343712SPeter Avalos {
18979343712SPeter Avalos 	struct timespec ts;
190e8af9738SPeter Avalos 	char buf[25];
19179343712SPeter Avalos 	static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL;
19279343712SPeter Avalos 	static const char *ref = "Sat Apr 23 01:30:00 1977";
19379343712SPeter Avalos 	char *p, *q;
19479343712SPeter Avalos 
19579343712SPeter Avalos 	cdf_timestamp_to_timespec(&ts, tst);
196e8af9738SPeter Avalos 	p = cdf_ctime(&ts.tv_sec, buf);
19779343712SPeter Avalos 	if ((q = strchr(p, '\n')) != NULL)
19879343712SPeter Avalos 		*q = '\0';
19979343712SPeter Avalos 	if (strcmp(ref, p) != 0)
20079343712SPeter Avalos 		errx(1, "Error date %s != %s\n", ref, p);
20179343712SPeter Avalos 	return 0;
20279343712SPeter Avalos }
20379343712SPeter Avalos #endif
204