blob: 2c29c40dd7981fe3605afc37130f1c4893066707 [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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 */
22
23#define _GNU_SOURCE
24#include <ctype.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "libnetconf.h"
31#include "netconf.h"
32
33API time_t
34nc_datetime2time(const char* datetime)
35{
36 struct tm time;
37 char* dt;
38 int i;
39 long int shift, shift_m;
40 time_t retval;
41
42 if (datetime == NULL) {
43 return (-1);
44 } else {
45 dt = strdup(datetime);
46 }
47
48 if (strlen(dt) < 20 || dt[4] != '-' || dt[7] != '-' || dt[13] != ':' || dt[16] != ':') {
49 ERR("Wrong date time format not compliant to RFC 3339.");
50 free(dt);
51 return (-1);
52 }
53
54 memset(&time, 0, sizeof(struct tm));
55 time.tm_year = atoi(&dt[0]) - 1900;
56 time.tm_mon = atoi(&dt[5]) - 1;
57 time.tm_mday = atoi(&dt[8]);
58 time.tm_hour = atoi(&dt[11]);
59 time.tm_min = atoi(&dt[14]);
60 time.tm_sec = atoi(&dt[17]);
61
62 retval = timegm(&time);
63
64 /* apply offset */
65 i = 19;
66 if (dt[i] == '.') { /* we have fractions to skip */
67 for (i++; isdigit(dt[i]); i++)
68 ;
69 }
70 if (dt[i] == 'Z' || dt[i] == 'z') {
71 /* zero shift */
72 shift = 0;
73 } else if (dt[i + 3] != ':') {
74 /* wrong format */
75 ERR("Wrong date time shift format not compliant to RFC 3339.");
76 free(dt);
77 return (-1);
78 } else {
79 shift = strtol(&dt[i], NULL, 10);
80 shift = shift * 60 * 60; /* convert from hours to seconds */
81 shift_m = strtol(&dt[i + 4], NULL, 10) * 60; /* includes conversion from minutes to seconds */
82 /* correct sign */
83 if (shift < 0) {
84 shift_m *= -1;
85 }
86 /* connect hours and minutes of the shift */
87 shift = shift + shift_m;
88 }
89 /* we have to shift to the opposite way to correct the time */
90 retval -= shift;
91
92 free(dt);
93 return (retval);
94}
95
96API char*
97nc_time2datetime(time_t time, const char* tz)
98{
99 char* date = NULL;
100 char* zoneshift = NULL;
101 int zonediff, zonediff_h, zonediff_m;
102 struct tm tm, *tm_ret;
103 char *tz_origin;
104
105 if (tz) {
106 tz_origin = getenv("TZ");
107 setenv("TZ", tz, 1);
108 tm_ret = localtime_r(&time, &tm);
109 setenv("TZ", tz_origin, 1);
110
111 if (tm_ret == NULL) {
112 return (NULL);
113 }
114 } else {
115 if (gmtime_r(&time, &tm) == NULL) {
116 return (NULL);
117 }
118 }
119
120 if (tm.tm_isdst < 0) {
121 zoneshift = NULL;
122 } else {
123 if (tm.tm_gmtoff == 0) {
124 /* time is Zulu (UTC) */
125 if (asprintf(&zoneshift, "Z") == -1) {
126 ERR("asprintf() failed (%s:%d).", __FILE__, __LINE__);
127 return (NULL);
128 }
129 } else {
130 zonediff = tm.tm_gmtoff;
131 zonediff_h = zonediff / 60 / 60;
132 zonediff_m = zonediff / 60 % 60;
133 if (asprintf(&zoneshift, "%s%02d:%02d", (zonediff < 0) ? "-" : "+", zonediff_h, zonediff_m) == -1) {
134 ERR("asprintf() failed (%s:%d).", __FILE__, __LINE__);
135 return (NULL);
136 }
137 }
138 }
139 if (asprintf(&date, "%04d-%02d-%02dT%02d:%02d:%02d%s",
140 tm.tm_year + 1900,
141 tm.tm_mon + 1,
142 tm.tm_mday,
143 tm.tm_hour,
144 tm.tm_min,
145 tm.tm_sec,
146 (zoneshift == NULL) ? "" : zoneshift) == -1) {
147 free(zoneshift);
148 ERR("asprintf() failed (%s:%d).", __FILE__, __LINE__);
149 return (NULL);
150 }
151 free(zoneshift);
152
153 return (date);
154}