1 /* @(#)mkgmtime.c	1.4 11/08/28 Copyright 2011 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)mkgmtime.c	1.4 11/08/28 Copyright 2011 J. Schilling";
6 #endif
7 /*
8  *	mkgmtime() is a complement to mktime()
9  *
10  *	Copyright (c) 2011 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/mconfig.h>
27 #include <schily/time.h>
28 #include <schily/utypes.h>
29 #include <schily/errno.h>
30 #include <schily/schily.h>
31 
32 EXPORT	Llong	mklgmtime	__PR((struct tm *tp));
33 EXPORT	time_t	mkgmtime	__PR((struct tm *tp));
34 
35 /*
36  * The Gregorian leap year formula
37  */
38 #define	dysize(A) (((A)%4)? 365 : (((A)%100) == 0 && ((A)%400)) ? 365 : 366)
39 #define	isleap(A) (((A)%4)? 0   : (((A)%100) == 0 && ((A)%400)) ? 0   : 1)
40 /*
41  * Return the number of leap years since 0 AD assuming that the Gregorian
42  * calendar applies to all years.
43  */
44 #define	LEAPS(Y) 	((Y) / 4 - (Y) / 100 + (Y) / 400)
45 /*
46  * Return the number of days since 0 AD
47  */
48 #define	YRDAYS(Y)	(((Y) * 365L) + LEAPS(Y))
49 /*
50  * Return the number of days between Januar 1 1970 and the end of the year
51  * before the the year used as argument.
52  */
53 #define	DAYS_SINCE_70(Y) (YRDAYS((Y)-1) - YRDAYS(1970-1))
54 
55 LOCAL	int dmbeg[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
56 
57 EXPORT Llong
mklgmtime(tp)58 mklgmtime(tp)
59 	struct tm	*tp;
60 {
61 	register Llong	tim;
62 
63 	if (tp->tm_mon >= 12) {
64 		tp->tm_year += tp->tm_mon / 12;
65 		tp->tm_mon %= 12;
66 	} else if (tp->tm_mon < 0) {
67 		int	m = -tp->tm_mon;
68 
69 		tp->tm_year -= m / 12;
70 		m %= 12;
71 		if (m) {
72 			tp->tm_year -= 1;
73 			tp->tm_mon = 12 - m;
74 		} else {
75 			tp->tm_mon = 0;
76 		}
77 	}
78 
79 	{
80 		register int	y = tp->tm_year + 1900;
81 		register int	t = tp->tm_mon;
82 
83 		tim = DAYS_SINCE_70(y);
84 
85 		if (t >= 2 && isleap(y))	/* March or later */
86 			tim += 1;		/* Add 29.2.	  */
87 		tim += dmbeg[t];
88 	}
89 
90 	tim += tp->tm_mday - 1;
91 	tim *= 24;
92 	tim += tp->tm_hour;
93 	tim *= 60;
94 	tim += tp->tm_min;
95 	tim *= 60;
96 	tim += tp->tm_sec;
97 	return (tim);
98 }
99 
100 EXPORT time_t
mkgmtime(tp)101 mkgmtime(tp)
102 	struct tm	*tp;
103 {
104 	Llong	tim;
105 	time_t	t;
106 
107 	t = tim = mklgmtime(tp);
108 	if (t != tim) {
109 #ifdef	EOVERFLOW
110 		seterrno(EOVERFLOW);
111 #else
112 		seterrno(EINVAL);
113 #endif
114 		return (-1);
115 	}
116 	return (t);
117 }
118