blob: 24f0017b45dd74997f3326c7afac93c0119619dd [file] [log] [blame]
Radek Krejcid0d19522015-09-02 13:49:25 +02001/**
2 * \file time.c
3 * \author Radek Krejci <rkrejci@cesnet.cz>
4 * \brief libnetconf2 - time handling functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vaskoafd416b2016-02-25 14:51:46 +010011 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejcid0d19522015-09-02 13:49:25 +020013 */
14
15#define _GNU_SOURCE
16#include <ctype.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21
22#include "libnetconf.h"
Radek Krejcid0d19522015-09-02 13:49:25 +020023
24API time_t
Michal Vasko231e4b22015-12-10 10:10:59 +010025nc_datetime2time(const char *datetime)
Radek Krejcid0d19522015-09-02 13:49:25 +020026{
27 struct tm time;
Michal Vasko231e4b22015-12-10 10:10:59 +010028 char *dt;
Radek Krejcid0d19522015-09-02 13:49:25 +020029 int i;
30 long int shift, shift_m;
31 time_t retval;
32
Michal Vasko7f1c78b2016-01-19 09:52:14 +010033 if (!datetime) {
34 ERRARG;
35 return -1;
Radek Krejcid0d19522015-09-02 13:49:25 +020036 }
37
Michal Vasko7f1c78b2016-01-19 09:52:14 +010038 dt = strdup(datetime);
39
Radek Krejcid0d19522015-09-02 13:49:25 +020040 if (strlen(dt) < 20 || dt[4] != '-' || dt[7] != '-' || dt[13] != ':' || dt[16] != ':') {
41 ERR("Wrong date time format not compliant to RFC 3339.");
42 free(dt);
43 return (-1);
44 }
45
46 memset(&time, 0, sizeof(struct tm));
47 time.tm_year = atoi(&dt[0]) - 1900;
48 time.tm_mon = atoi(&dt[5]) - 1;
49 time.tm_mday = atoi(&dt[8]);
50 time.tm_hour = atoi(&dt[11]);
51 time.tm_min = atoi(&dt[14]);
52 time.tm_sec = atoi(&dt[17]);
53
54 retval = timegm(&time);
55
56 /* apply offset */
57 i = 19;
58 if (dt[i] == '.') { /* we have fractions to skip */
59 for (i++; isdigit(dt[i]); i++)
60 ;
61 }
62 if (dt[i] == 'Z' || dt[i] == 'z') {
63 /* zero shift */
64 shift = 0;
65 } else if (dt[i + 3] != ':') {
66 /* wrong format */
67 ERR("Wrong date time shift format not compliant to RFC 3339.");
68 free(dt);
69 return (-1);
70 } else {
71 shift = strtol(&dt[i], NULL, 10);
72 shift = shift * 60 * 60; /* convert from hours to seconds */
73 shift_m = strtol(&dt[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
74 /* correct sign */
75 if (shift < 0) {
76 shift_m *= -1;
77 }
78 /* connect hours and minutes of the shift */
79 shift = shift + shift_m;
80 }
81 /* we have to shift to the opposite way to correct the time */
82 retval -= shift;
83
84 free(dt);
Michal Vasko7f1c78b2016-01-19 09:52:14 +010085 return retval;
Radek Krejcid0d19522015-09-02 13:49:25 +020086}
87
Michal Vasko231e4b22015-12-10 10:10:59 +010088API char *
89nc_time2datetime(time_t time, const char *tz)
Radek Krejcid0d19522015-09-02 13:49:25 +020090{
Michal Vasko231e4b22015-12-10 10:10:59 +010091 char *date = NULL;
92 char *zoneshift = NULL;
Radek Krejcid0d19522015-09-02 13:49:25 +020093 int zonediff, zonediff_h, zonediff_m;
94 struct tm tm, *tm_ret;
95 char *tz_origin;
96
97 if (tz) {
Michal Vasko11d142a2016-01-19 15:58:24 +010098 tz_origin = secure_getenv("TZ");
Radek Krejcid0d19522015-09-02 13:49:25 +020099 setenv("TZ", tz, 1);
100 tm_ret = localtime_r(&time, &tm);
101 setenv("TZ", tz_origin, 1);
102
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100103 if (!tm_ret) {
104 return NULL;
Radek Krejcid0d19522015-09-02 13:49:25 +0200105 }
106 } else {
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100107 if (!gmtime_r(&time, &tm)) {
108 return NULL;
Radek Krejcid0d19522015-09-02 13:49:25 +0200109 }
110 }
111
112 if (tm.tm_isdst < 0) {
113 zoneshift = NULL;
114 } else {
115 if (tm.tm_gmtoff == 0) {
116 /* time is Zulu (UTC) */
117 if (asprintf(&zoneshift, "Z") == -1) {
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100118 ERRMEM;
119 return NULL;
Radek Krejcid0d19522015-09-02 13:49:25 +0200120 }
121 } else {
122 zonediff = tm.tm_gmtoff;
123 zonediff_h = zonediff / 60 / 60;
124 zonediff_m = zonediff / 60 % 60;
125 if (asprintf(&zoneshift, "%s%02d:%02d", (zonediff < 0) ? "-" : "+", zonediff_h, zonediff_m) == -1) {
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100126 ERRMEM;
127 return NULL;
Radek Krejcid0d19522015-09-02 13:49:25 +0200128 }
129 }
130 }
131 if (asprintf(&date, "%04d-%02d-%02dT%02d:%02d:%02d%s",
132 tm.tm_year + 1900,
133 tm.tm_mon + 1,
134 tm.tm_mday,
135 tm.tm_hour,
136 tm.tm_min,
137 tm.tm_sec,
138 (zoneshift == NULL) ? "" : zoneshift) == -1) {
139 free(zoneshift);
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100140 ERRMEM;
141 return NULL;
Radek Krejcid0d19522015-09-02 13:49:25 +0200142 }
143 free(zoneshift);
144
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100145 return date;
Radek Krejcid0d19522015-09-02 13:49:25 +0200146}