1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Bacula floating point time and date routines -- John Walker
21  *
22  * Later double precision integer time/date routines -- Kern Sibbald
23  *
24  */
25 
26 /*
27  * Concerning times. There are a number of different time standards
28  * in Bacula (fdate_t, ftime_t, time_t (Unix standard), btime_t, and
29  *  utime_t).  fdate_t and ftime_t are deprecated and should no longer
30  *  be used, and in general, Unix time time_t should no longer be used,
31  *  it is being phased out.
32  *
33  *  Epoch is the base of Unix time in seconds (time_t, ...)
34  *     and is 1 Jan 1970 at 0:0 UTC
35  *
36  *  The major two times that should be left are:
37  *     btime_t  (64 bit integer in microseconds base Epoch)
38  *     utime_t  (64 bit integer in seconds base Epoch)
39  */
40 
41 #include "bacula.h"
42 #include <math.h>
43 
44 /* Formatted time for catalog: yyymmddhhmmss */
bstrftime_c(char * dt,int maxlen,utime_t utime)45 char *bstrftime_c(char *dt, int maxlen, utime_t utime)
46 {
47    time_t time = (time_t)utime;
48    struct tm tm;
49 
50    /* ***FIXME**** the format and localtime_r() should be user configurable */
51    (void)localtime_r(&time, &tm);
52    strftime(dt, maxlen, "%Y%m%d%H%m%S", &tm);
53    return dt;
54 }
55 
56 /* Formatted time for user display: dd-Mon-yyyy hh:mm */
bstrftime(char * dt,int maxlen,utime_t utime)57 char *bstrftime(char *dt, int maxlen, utime_t utime)
58 {
59    time_t time = (time_t)utime;
60    struct tm tm;
61 
62    /* ***FIXME**** the format and localtime_r() should be user configurable */
63    (void)localtime_r(&time, &tm);
64    strftime(dt, maxlen, "%d-%b-%Y %H:%M", &tm);
65    return dt;
66 }
67 
bstrftimes_na(char * dt,int maxlen,utime_t utime)68 char *bstrftimes_na(char *dt, int maxlen, utime_t utime)
69 {
70    if (utime == 0) {
71       return bstrncpy(dt, "", maxlen);
72    } else {
73       return bstrftimes(dt, maxlen, utime);
74    }
75 }
76 
77 /* Formatted time for user display: dd-Mon-yyyy hh:mm:ss */
bstrftimes(char * dt,int maxlen,utime_t utime)78 char *bstrftimes(char *dt, int maxlen, utime_t utime)
79 {
80    time_t time = (time_t)utime;
81    struct tm tm;
82 
83    /* ***FIXME**** the format and localtime_r() should be user configurable */
84    (void)localtime_r(&time, &tm);
85    strftime(dt, maxlen, "%d-%b-%Y %H:%M:%S", &tm);
86    return dt;
87 }
88 
89 /* Formatted time with day name for user display: dd-Mon hh:mm */
bstrftime_dn(char * dt,int maxlen,utime_t utime)90 char *bstrftime_dn(char *dt, int maxlen, utime_t utime)
91 {
92    time_t time = (time_t)utime;
93    struct tm tm;
94 
95    /* ***FIXME**** the format and localtime_r() should be user configurable */
96    (void)localtime_r(&time, &tm);
97    strftime(dt, maxlen, "%a %d-%b %H:%M", &tm);
98    return dt;
99 }
100 
101 /* Formatted time (no year) for user display: dd-Mon hh:mm */
bstrftime_ny(char * dt,int maxlen,utime_t utime)102 char *bstrftime_ny(char *dt, int maxlen, utime_t utime)
103 {
104    time_t time = (time_t)utime;
105    struct tm tm;
106 
107    /* ***FIXME**** the format and localtime_r() should be user configurable */
108    (void)localtime_r(&time, &tm);
109    strftime(dt, maxlen, "%d-%b %H:%M", &tm);
110    return dt;
111 }
112 
113 
114 /* Formatted time for user display: dd-Mon-yy hh:mm  (no century) */
bstrftime_nc(char * dt,int maxlen,utime_t utime)115 char *bstrftime_nc(char *dt, int maxlen, utime_t utime)
116 {
117    time_t time = (time_t)utime;
118    struct tm tm;
119    char *p, *q;
120 
121    /* ***FIXME**** the format and localtime_r() should be user configurable */
122    (void)localtime_r(&time, &tm);
123    /* NOTE! since the compiler complains about %y, I use %y and cut the century */
124    strftime(dt, maxlen, "%d-%b-%Y %H:%M", &tm);
125    /* overlay the century */
126    p = dt+7;
127    q = dt+9;
128    while (*q) {
129       *p++ = *q++;
130    }
131    *p = 0;
132    return dt;
133 }
134 
135 
136 /* Unix time to standard time string yyyy-mm-dd hh:mm:ss */
bstrutime(char * dt,int maxlen,utime_t utime)137 char *bstrutime(char *dt, int maxlen, utime_t utime)
138 {
139    time_t time = (time_t)utime;
140    struct tm tm;
141    (void)localtime_r(&time, &tm);
142    strftime(dt, maxlen, "%Y-%m-%d %H:%M:%S", &tm);
143    return dt;
144 }
145 
146 /* Convert standard time string yyyy-mm-dd hh:mm:ss to Unix time */
str_to_utime(char * str)147 utime_t str_to_utime(char *str)
148 {
149    struct tm tm;
150    time_t time;
151 
152    /* Minimal check for bad argument */
153    if (!str || *str == 0 || (strlen(str) != 19) ||
154        (str[4] != '-') || (str[7] != '-') ||
155        (str[13] != ':') || (str[16] != ':')) {
156       return 0;
157    }
158 
159    if (sscanf(str, "%d-%d-%d %d:%d:%d", &tm.tm_year,
160        &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
161       return 0;
162    }
163    if (tm.tm_mon > 0) {
164       tm.tm_mon--;
165    } else {
166       return 0;
167    }
168    if (tm.tm_year >= 1900) {
169       tm.tm_year -= 1900;
170    } else {
171       return 0;
172    }
173    tm.tm_wday = tm.tm_yday = 0;
174    tm.tm_isdst = -1;
175    time = mktime(&tm);
176    if (time == -1) {
177       time = 0;
178    }
179    return (utime_t)time;
180 }
181 
182 
183 /*
184  * Bacula's time (btime_t) is an unsigned 64 bit integer that contains
185  *   the number of microseconds since Epoch Time (1 Jan 1970) UTC.
186  */
187 
get_current_btime()188 btime_t get_current_btime()
189 {
190    struct timeval tv;
191    if (gettimeofday(&tv, NULL) != 0) {
192       tv.tv_sec = (long)time(NULL);   /* fall back to old method */
193       tv.tv_usec = 0;
194    }
195    return ((btime_t)tv.tv_sec) * 1000000 + (btime_t)tv.tv_usec;
196 }
197 
198 /* Convert btime to Unix time */
btime_to_unix(btime_t bt)199 time_t btime_to_unix(btime_t bt)
200 {
201    return (time_t)(bt/1000000);
202 }
203 
204 /* Convert btime to utime */
btime_to_utime(btime_t bt)205 utime_t btime_to_utime(btime_t bt)
206 {
207    return (utime_t)(bt/1000000);
208 }
209 
210 /*
211  * Definition of a leap year from Wikipedia.
212  *  I knew it anyway but better check.
213  */
is_leap_year(int year)214 static bool is_leap_year(int year)
215 {
216    if (year % 400 == 0) return true;
217    if (year % 100 == 0) return false;
218    if (year % 4 == 0) return true;
219    return false;
220 }
221 
222 /*
223  * Return the last day of the month, base 0
224  *   month=0-11, year is actual year
225  *   ldom is base 0
226  */
tm_ldom(int month,int year)227 int tm_ldom(int month, int year)
228 {                     /* jan feb mar apr may jun jul aug sep oct nov dec */
229    static int dom[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
230 
231    if (is_leap_year(year) && month == 1) return 28;
232    return dom[month] - 1;
233 }
234 
235 /*
236  * Return the week of the month, base 0 (wom)
237  *   given tm_mday and tm_wday. Value returned
238  *   can be from 0 to 5 => week1, ... week6
239  */
tm_wom(int mday,int wday)240 int tm_wom(int mday, int wday)
241 {
242    int fs;                       /* first sunday */
243    fs = (mday%7) - wday;
244    if (fs <= 0) {
245       fs += 7;
246    }
247    if (mday <= fs) {
248 //    Dmsg3(100, "mday=%d wom=0 wday=%d <= fs=%d\n", mday, wday, fs);
249       return 0;
250    }
251    int wom = 1 + (mday - fs - 1) / 7;
252 // Dmsg4(100, "mday=%d wom=%d wday=%d fs=%d\n", mday, wom, wday, fs);
253    return wom;
254 }
255 
256 /*
257  * Given a Unix date return the week of the year.
258  * The returned value can be 0-53.  Officially
259  * the weeks are numbered from 1 to 53 where week1
260  * is the week in which the first Thursday of the
261  * year occurs (alternatively, the week which contains
262  * the 4th of January).  We return 0, if the week of the
263  * year does not fall in the current year.
264  */
tm_woy(time_t stime)265 int tm_woy(time_t stime)
266 {
267    int woy, fty, tm_yday;
268    time_t time4;
269    struct tm tm;
270 
271    memset(&tm, 0, sizeof(struct tm));
272    (void)localtime_r(&stime, &tm);
273    tm_yday = tm.tm_yday;
274    tm.tm_mon = 0;
275    tm.tm_mday = 4;
276    tm.tm_isdst = 0;                   /* 4 Jan is not DST */
277    time4 = mktime(&tm);
278    (void)localtime_r(&time4, &tm);
279    fty = 1 - tm.tm_wday;
280    if (fty <= 0) {
281       fty += 7;
282    }
283    woy = tm_yday - fty + 4;
284    if (woy < 0) {
285       return 0;
286    }
287    return 1 + woy / 7;
288 }
289 
290 /* Deprecated. Do not use. */
get_current_time(struct date_time * dt)291 void get_current_time(struct date_time *dt)
292 {
293    struct tm tm;
294    time_t now;
295 
296    now = time(NULL);
297    (void)gmtime_r(&now, &tm);
298    Dmsg6(200, "m=%d d=%d y=%d h=%d m=%d s=%d\n", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900,
299       tm.tm_hour, tm.tm_min, tm.tm_sec);
300    tm_encode(dt, &tm);
301 #ifdef DEBUG
302    Dmsg2(200, "jday=%f jmin=%f\n", dt->julian_day_number, dt->julian_day_fraction);
303    tm_decode(dt, &tm);
304    Dmsg6(200, "m=%d d=%d y=%d h=%d m=%d s=%d\n", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900,
305       tm.tm_hour, tm.tm_min, tm.tm_sec);
306 #endif
307 }
308 
309 
310 
311 /*  date_encode  --  Encode civil date as a Julian day number.  */
312 /* Deprecated. Do not use. */
date_encode(uint32_t year,uint8_t month,uint8_t day)313 fdate_t date_encode(uint32_t year, uint8_t month, uint8_t day)
314 {
315 
316     /* Algorithm as given in Meeus, Astronomical Algorithms, Chapter 7, page 61 */
317 
318     int32_t a, b, m;
319     uint32_t y;
320 
321     ASSERT(month < 13);
322     ASSERT(day > 0 && day < 32);
323 
324     m = month;
325     y = year;
326 
327     if (m <= 2) {
328         y--;
329         m += 12;
330     }
331 
332     /* Determine whether date is in Julian or Gregorian calendar based on
333        canonical date of calendar reform. */
334 
335     if ((year < 1582) || ((year == 1582) && ((month < 9) || (month == 9 && day < 5)))) {
336         b = 0;
337     } else {
338         a = ((int) (y / 100));
339         b = 2 - a + (a / 4);
340     }
341 
342     return (((int32_t) (365.25 * (y + 4716))) + ((int) (30.6001 * (m + 1))) +
343                 day + b - 1524.5);
344 }
345 
346 /*  time_encode  --  Encode time from hours, minutes, and seconds
347                      into a fraction of a day.  */
348 
349 /* Deprecated. Do not use. */
time_encode(uint8_t hour,uint8_t minute,uint8_t second,float32_t second_fraction)350 ftime_t time_encode(uint8_t hour, uint8_t minute, uint8_t second,
351                    float32_t second_fraction)
352 {
353     ASSERT((second_fraction >= 0.0) || (second_fraction < 1.0));
354     return (ftime_t) (((second + 60L * (minute + 60L * hour)) / 86400.0)) +
355                      second_fraction;
356 }
357 
358 /*  date_time_encode  --  Set day number and fraction from date
359                           and time.  */
360 
361 /* Deprecated. Do not use. */
date_time_encode(struct date_time * dt,uint32_t year,uint8_t month,uint8_t day,uint8_t hour,uint8_t minute,uint8_t second,float32_t second_fraction)362 void date_time_encode(struct date_time *dt,
363                       uint32_t year, uint8_t month, uint8_t day,
364                       uint8_t hour, uint8_t minute, uint8_t second,
365                       float32_t second_fraction)
366 {
367     dt->julian_day_number = date_encode(year, month, day);
368     dt->julian_day_fraction = time_encode(hour, minute, second, second_fraction);
369 }
370 
371 /*  date_decode  --  Decode a Julian day number into civil date.  */
372 
373 /* Deprecated. Do not use. */
date_decode(fdate_t date,uint32_t * year,uint8_t * month,uint8_t * day)374 void date_decode(fdate_t date, uint32_t *year, uint8_t *month,
375                  uint8_t *day)
376 {
377     fdate_t z, f, a, alpha, b, c, d, e;
378 
379     date += 0.5;
380     z = floor(date);
381     f = date - z;
382 
383     if (z < 2299161.0) {
384         a = z;
385     } else {
386         alpha = floor((z - 1867216.25) / 36524.25);
387         a = z + 1 + alpha - floor(alpha / 4);
388     }
389 
390     b = a + 1524;
391     c = floor((b - 122.1) / 365.25);
392     d = floor(365.25 * c);
393     e = floor((b - d) / 30.6001);
394 
395     *day = (uint8_t) (b - d - floor(30.6001 * e) + f);
396     *month = (uint8_t) ((e < 14) ? (e - 1) : (e - 13));
397     *year = (uint32_t) ((*month > 2) ? (c - 4716) : (c - 4715));
398 }
399 
400 /*  time_decode  --  Decode a day fraction into civil time.  */
401 
402 /* Deprecated. Do not use. */
time_decode(ftime_t time,uint8_t * hour,uint8_t * minute,uint8_t * second,float32_t * second_fraction)403 void time_decode(ftime_t time, uint8_t *hour, uint8_t *minute,
404                  uint8_t *second, float32_t *second_fraction)
405 {
406     uint32_t ij;
407 
408     ij = (uint32_t) ((time - floor(time)) * 86400.0);
409     *hour = (uint8_t) (ij / 3600L);
410     *minute = (uint8_t) ((ij / 60L) % 60L);
411     *second = (uint8_t) (ij % 60L);
412     if (second_fraction != NULL) {
413         *second_fraction = (float32_t)(time - floor(time));
414     }
415 }
416 
417 /*  date_time_decode  --  Decode a Julian day and day fraction
418                           into civil date and time.  */
419 
420 /* Deprecated. Do not use. */
date_time_decode(struct date_time * dt,uint32_t * year,uint8_t * month,uint8_t * day,uint8_t * hour,uint8_t * minute,uint8_t * second,float32_t * second_fraction)421 void date_time_decode(struct date_time *dt,
422                       uint32_t *year, uint8_t *month, uint8_t *day,
423                       uint8_t *hour, uint8_t *minute, uint8_t *second,
424                       float32_t *second_fraction)
425 {
426     date_decode(dt->julian_day_number, year, month, day);
427     time_decode(dt->julian_day_fraction, hour, minute, second, second_fraction);
428 }
429 
430 /*  tm_encode  --  Encode a civil date and time from a tm structure
431  *                 to a Julian day and day fraction.
432  */
433 
434 /* Deprecated. Do not use. */
tm_encode(struct date_time * dt,struct tm * tm)435 void tm_encode(struct date_time *dt,
436                       struct tm *tm)
437 {
438     uint32_t year;
439     uint8_t month, day, hour, minute, second;
440 
441     year = tm->tm_year + 1900;
442     month = tm->tm_mon + 1;
443     day = tm->tm_mday;
444     hour = tm->tm_hour;
445     minute = tm->tm_min;
446     second = tm->tm_sec;
447     dt->julian_day_number = date_encode(year, month, day);
448     dt->julian_day_fraction = time_encode(hour, minute, second, 0.0);
449 }
450 
451 
452 /*  tm_decode  --  Decode a Julian day and day fraction
453                    into civil date and time in tm structure */
454 
455 /* Deprecated. Do not use. */
tm_decode(struct date_time * dt,struct tm * tm)456 void tm_decode(struct date_time *dt,
457                       struct tm *tm)
458 {
459     uint32_t year;
460     uint8_t month, day, hour, minute, second;
461 
462     date_decode(dt->julian_day_number, &year, &month, &day);
463     time_decode(dt->julian_day_fraction, &hour, &minute, &second, NULL);
464     tm->tm_year = year - 1900;
465     tm->tm_mon = month - 1;
466     tm->tm_mday = day;
467     tm->tm_hour = hour;
468     tm->tm_min = minute;
469     tm->tm_sec = second;
470 }
471 
472 
473 /*  date_time_compare  --  Compare two dates and times and return
474                            the relationship as follows:
475 
476                                     -1    dt1 < dt2
477                                      0    dt1 = dt2
478                                      1    dt1 > dt2
479 */
480 
481 /* Deprecated. Do not use. */
date_time_compare(struct date_time * dt1,struct date_time * dt2)482 int date_time_compare(struct date_time *dt1, struct date_time *dt2)
483 {
484     if (dt1->julian_day_number == dt2->julian_day_number) {
485         if (dt1->julian_day_fraction == dt2->julian_day_fraction) {
486             return 0;
487         }
488         return (dt1->julian_day_fraction < dt2->julian_day_fraction) ? -1 : 1;
489     }
490     return (dt1->julian_day_number - dt2->julian_day_number) ? -1 : 1;
491 }
492