3 * MAKETIME derive 32-bit time value from TM structure.
7 * struct tm *tp; Pointer to TM structure from <time.h>
8 * NOTE: this must be extended version!!!
12 * 0 if failure; parameter out of range or nonsensical.
13 * else long time-value.
15 * This code is quasi-public; it may be used freely in like software.
16 * It is not to be sold, nor used in licensed software without
17 * permission of the author.
18 * For everyone's benefit, please report bugs and improvements!
19 * Copyright 1981 by Ken Harrenstien, SRI International.
20 * (ARPANET: KLH @ SRI)
23 static char rcsid
[]= "$Id: maketime.c,v 1.1 1993/03/21 09:58:06 cgd Exp $";
25 /* $Log: maketime.c,v $
26 * Revision 1.8 88/11/08 13:54:53 narten
27 * allow negative timezones (-24h <= x <= 24h)
29 * Revision 1.7 88/11/08 12:02:24 narten
30 * changes from eggert@sm.unisys.com (Paul Eggert)
32 * Revision 1.7 88/08/28 14:47:52 eggert
33 * Allow cc -R. Remove unportable "#endif XXX"s.
35 * Revision 1.6 87/12/18 17:05:58 narten
38 * Revision 1.5 87/12/18 11:35:51 narten
39 * maketime.c: fixed USG code - you have tgo call "tzset" in order to have
40 * "timezone" set. ("localtime" calls it, but it's probably better not to
41 * count on "localtime" having been called.)
43 * Revision 1.4 87/10/18 10:26:57 narten
44 * Updating version numbers. Changes relative to 1.0 are actually
47 * Revision 1.3 87/09/24 13:58:45 narten
48 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
51 * Revision 1.2 87/03/27 14:21:48 jenkins
54 * Revision 1.1 84/01/23 14:50:04 kcs
57 * Revision 1.2 83/12/05 10:12:56 wft
58 * added cond. compilation for USG Unix; long timezone;
60 * Revision 1.1 82/05/06 11:38:00 wft
69 int daytb
[] = { /* # days in year thus far, indexed by month (0-12!!) */
70 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
73 struct tm
*localtime();
78 { register struct tm
*tp
;
80 int year
, yday
, mon
, day
, hour
, min
, sec
, zone
, dst
, leap
;
84 tp
= localtime(&curtim
); /* Get breakdowns of current time */
85 year
= tp
->tm_year
; /* Use to set up defaults */
91 printf("first YMD: %d %d %d, T=%ld\n",year
,mon
,day
,tres
);
95 /* First must find date, using specified year, month, day.
96 * If one of these is unspecified, it defaults either to the
97 * current date (if no more global spec was given) or to the
98 * zero-value for that spec (i.e. a more global spec was seen).
99 * Start with year... note 32 bits can only handle 135 years.
101 if(tp
->tm_year
!= TMNULL
)
102 { if((year
= tp
->tm_year
) >= 1900) /* Allow full yr # */
103 year
-= 1900; /* by making kosher */
104 mon
= 0; /* Since year was given, default */
105 day
= 1; /* for remaining specs is zero */
107 if(year
< 70 || 70+134 < year
) /* Check range */
108 return(0); /* ERR: year out of range */
109 leap
= year
&03 ? 0 : 1; /* See if leap year */
110 year
-= 70; /* UNIX time starts at 1970 */
114 * YDAY is used only if it exists and either the month or day-of-month
117 if (tp
->tm_yday
!= TMNULL
118 && (tp
->tm_mon
== TMNULL
|| tp
->tm_mday
== TMNULL
))
121 { if(tp
->tm_mon
!= TMNULL
)
122 { mon
= tp
->tm_mon
; /* Month was specified */
123 day
= 1; /* so set remaining default */
125 if(mon
< 0 || 11 < mon
) return(0); /* ERR: bad month */
126 if(tp
->tm_mday
!= TMNULL
) day
= tp
->tm_mday
;
128 || (((daytb
[mon
+1]-daytb
[mon
]) < day
)
129 && (day
!=29 || mon
!=1 || !leap
) ))
130 return(0); /* ERR: bad day */
131 yday
= daytb
[mon
] /* Add # of days in months so far */
132 + ((leap
/* Leap year, and past Feb? If */
133 && mon
>1)? 1:0) /* so, add leap day for this year */
134 + day
-1; /* And finally add # days this mon */
136 if (tp
->tm_yday
!= TMNULL
/* Confirm that YDAY correct */
137 && tp
->tm_yday
!= yday
) return(0); /* ERR: conflict */
139 if(yday
< 0 || (leap
?366:365) <= yday
)
140 return(0); /* ERR: bad YDAY or maketime bug */
142 tres
= year
*365 /* Get # days of years so far */
143 + ((year
+1)>>2) /* plus # of leap days since 1970 */
144 + yday
; /* and finally add # days this year */
146 if((i
= tp
->tm_wday
) != TMNULL
) /* Check WDAY if present */
147 if(i
< 0 || 6 < i
/* Ensure within range */
148 || i
!= (tres
+4)%7) /* Matches? Jan 1,1970 was Thu = 4 */
149 return(0); /* ERR: bad WDAY */
152 printf("YMD: %d %d %d, T=%ld\n",year
,mon
,day
,tres
);
155 * Now determine time. If not given, default to zeros
156 * (since time is always the least global spec)
158 tres
*= 86400L; /* Get # seconds (24*60*60) */
159 hour
= min
= sec
= 0;
160 if(tp
->tm_hour
!= TMNULL
) hour
= tp
->tm_hour
;
161 if(tp
->tm_min
!= TMNULL
) min
= tp
->tm_min
;
162 if(tp
->tm_sec
!= TMNULL
) sec
= tp
->tm_sec
;
163 if( min
< 0 || 60 <= min
164 || sec
< 0 || 60 <= sec
) return(0); /* ERR: MS out of range */
165 if(hour
< 0 || 24 <= hour
)
166 if(hour
!= 24 || (min
+sec
) !=0) /* Allow 24:00 */
167 return(0); /* ERR: H out of range */
169 /* confirm AM/PM if there */
171 { case 0: case TMNULL
: /* Ignore these values */
175 if(hour
> 12) return(0); /* ERR: hrs 13-23 bad */
176 if(hour
==12) hour
= 0; /* Modulo 12 */
177 if(tp
->tm_ampm
== 2) /* If PM, then */
178 hour
+= 12; /* get 24-hour time */
180 default: return(0); /* ERR: illegal TM_AMPM value */
183 tres
+= sec
+ 60L*(min
+ 60L*hour
); /* Add in # secs of time */
186 printf("HMS: %d %d %d T=%ld\n",hour
,min
,sec
,tres
);
189 * We now have the GMT date/time and must make final
190 * adjustment for the specified time zone. If none is specified,
191 * the local time-zone is assumed.
193 if((zone
= tp
->tm_zon
) == TMNULL
/* If unspecified */
194 || (zone
== 1)) /* or local-zone requested */
195 zone
= localzone(); /* then set to local zone */
196 if(zone
< -24*60 || 24*60 <= zone
)
197 return(0); /* ERR: zone out of range */
199 /* See if must apply Daylight Saving Time shift.
200 * Note that if DST is specified, validity is not checked.
202 if((dst
= tp
->tm_isdst
) == TMNULL
) /* Must we figure it out? */
203 { curtim
= tres
+localzone()*60L; /* Yuck. Get equiv local */
204 dst
= localtime(&curtim
)->tm_isdst
; /* time, and ask. */
206 tres
+= zone
*60L -(dst
?3600:0); /* Add in # seconds of zone adj */