1 /* Convert between RCS time format and Posix and/or C formats.  */
2 
3 /* Copyright 1992, 1993, 1994, 1995 Paul Eggert
4    Distributed under license by the Free Software Foundation, Inc.
5 
6 This file is part of RCS.
7 
8 RCS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12 
13 RCS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with RCS; see the file COPYING.
20 If not, write to the Free Software Foundation,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 Report problems and direct all questions to:
24 
25     rcs-bugs@cs.purdue.edu
26 
27 */
28 
29 #include "rcsbase.h"
30 #include "partime.h"
31 #include "maketime.h"
32 
33 libId(rcstimeId, "$FreeBSD: stable/9/gnu/usr.bin/rcs/lib/rcstime.c 50472 1999-08-27 23:37:10Z peter $")
34 
35 static long zone_offset; /* seconds east of UTC, or TM_LOCAL_ZONE */
36 static int use_zone_offset; /* if zero, use UTC without zone indication */
37 
38 /*
39 * Convert Unix time to RCS format.
40 * For compatibility with older versions of RCS,
41 * dates from 1900 through 1999 are stored without the leading "19".
42 */
43 	void
time2date(unixtime,date)44 time2date(unixtime,date)
45 	time_t unixtime;
46 	char date[datesize];
47 {
48 	register struct tm const *tm = time2tm(unixtime, RCSversion<VERSION(5));
49 	VOID sprintf(date,
50 #		if has_printf_dot
51 			"%.2d.%.2d.%.2d.%.2d.%.2d.%.2d",
52 #		else
53 			"%02d.%02d.%02d.%02d.%02d.%02d",
54 #		endif
55 		tm->tm_year  +  ((unsigned)tm->tm_year < 100 ? 0 : 1900),
56 		tm->tm_mon+1, tm->tm_mday,
57 		tm->tm_hour, tm->tm_min, tm->tm_sec
58 	);
59 }
60 
61 /* Like str2time, except die if an error was found.  */
62 static time_t str2time_checked P((char const*,time_t,long));
63 	static time_t
str2time_checked(source,default_time,default_zone)64 str2time_checked(source, default_time, default_zone)
65 	char const *source;
66 	time_t default_time;
67 	long default_zone;
68 {
69 	time_t t = str2time(source, default_time, default_zone);
70 	if (t == -1)
71 		faterror("unknown date/time: %s", source);
72 	return t;
73 }
74 
75 /*
76 * Parse a free-format date in SOURCE, convert it
77 * into RCS internal format, and store the result into TARGET.
78 */
79 	void
str2date(source,target)80 str2date(source, target)
81 	char const *source;
82 	char target[datesize];
83 {
84 	time2date(
85 		str2time_checked(source, now(),
86 			use_zone_offset ? zone_offset
87 			: RCSversion<VERSION(5) ? TM_LOCAL_ZONE
88 			: 0
89 		),
90 		target
91 	);
92 }
93 
94 /* Convert an RCS internal format date to time_t.  */
95 	time_t
date2time(source)96 date2time(source)
97 	char const source[datesize];
98 {
99 	char s[datesize + zonelenmax];
100 	return str2time_checked(date2str(source, s), (time_t)0, 0);
101 }
102 
103 
104 /* Set the time zone for date2str output.  */
105 	void
zone_set(s)106 zone_set(s)
107 	char const *s;
108 {
109 	if ((use_zone_offset = *s)) {
110 		long zone;
111 		char const *zonetail = parzone(s, &zone);
112 		if (!zonetail || *zonetail)
113 			error("%s: not a known time zone", s);
114 		else
115 			zone_offset = zone;
116 	}
117 }
118 
119 
120 /*
121 * Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
122 * Yield DATEBUF.
123 */
124 	char const *
date2str(date,datebuf)125 date2str(date, datebuf)
126 	char const date[datesize];
127 	char datebuf[datesize + zonelenmax];
128 {
129 	register char const *p = date;
130 
131 	while (*p++ != '.')
132 		continue;
133 	if (!use_zone_offset)
134 	    VOID sprintf(datebuf,
135 		"19%.*s/%.2s/%.2s %.2s:%.2s:%s"
136 			+ (date[2]=='.' && VERSION(5)<=RCSversion  ?  0  :  2),
137 		(int)(p-date-1), date,
138 		p, p+3, p+6, p+9, p+12
139 	    );
140 	else {
141 	    struct tm t;
142 	    struct tm const *z;
143 	    int non_hour;
144 	    long zone;
145 	    char c;
146 
147 	    t.tm_year = atoi(date) - (date[2]=='.' ? 0 : 1900);
148 	    t.tm_mon = atoi(p) - 1;
149 	    t.tm_mday = atoi(p+3);
150 	    t.tm_hour = atoi(p+6);
151 	    t.tm_min = atoi(p+9);
152 	    t.tm_sec = atoi(p+12);
153 	    t.tm_wday = -1;
154 	    zone = zone_offset;
155 	    if (zone == TM_LOCAL_ZONE) {
156 		time_t u = tm2time(&t, 0), d;
157 		z = localtime(&u);
158 		d = difftm(z, &t);
159 		zone  =  (time_t)-1 < 0 || d < -d  ?  d  :  -(long)-d;
160 	    } else {
161 		adjzone(&t, zone);
162 		z = &t;
163 	    }
164 	    c = '+';
165 	    if (zone < 0) {
166 		zone = -zone;
167 		c = '-';
168 	    }
169 	    VOID sprintf(datebuf,
170 #		if has_printf_dot
171 		    "%.2d-%.2d-%.2d %.2d:%.2d:%.2d%c%.2d",
172 #		else
173 		    "%02d-%02d-%02d %02d:%02d:%02d%c%02d",
174 #		endif
175 		z->tm_year + 1900,
176 		z->tm_mon + 1, z->tm_mday, z->tm_hour, z->tm_min, z->tm_sec,
177 		c, (int) (zone / (60*60))
178 	    );
179 	    if ((non_hour = zone % (60*60))) {
180 #		if has_printf_dot
181 		    static char const fmt[] = ":%.2d";
182 #		else
183 		    static char const fmt[] = ":%02d";
184 #		endif
185 		VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour / 60);
186 		if ((non_hour %= 60))
187 		    VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour);
188 	    }
189 	}
190 	return datebuf;
191 }
192