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