2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

timestamp.cpp 7.64 KB
Newer Older
1
2
3
//================================================================================
// Name        : timestamp.cpp
// Author      : Axel Auweter, Michael Ott
Micha Müller's avatar
Micha Müller committed
4
// Contact     : info@dcdb.it
5
// Copyright   : Leibniz Supercomputing Centre
Michael Ott's avatar
Michael Ott committed
6
// Description : C++ API for handling time stamps in libdcdb.
7
8
9
10
//================================================================================

//================================================================================
// This file is part of DCDB (DataCenter DataBase)
11
// Copyright (C) 2011-2019 Leibniz Supercomputing Centre
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//================================================================================
Axel Auweter's avatar
Axel Auweter committed
27
28
29
30
31

#include <cstring>
#include <cinttypes>

#include "boost/date_time/posix_time/posix_time.hpp"
32
33
#include "boost/date_time/local_time/local_time.hpp"
#include "boost/date_time/c_local_time_adjustor.hpp"
34
#include "boost/regex.hpp"
Axel Auweter's avatar
Axel Auweter committed
35

36
#include "dcdb/timestamp.h"
Axel Auweter's avatar
Axel Auweter committed
37

38
39
using namespace DCDB;

40
41
/* Use this as our local to utc adjustor */
typedef boost::date_time::c_local_adjustor<boost::posix_time::ptime> local_adj;
Axel Auweter's avatar
Axel Auweter committed
42
43
44
45
46
47

/**
 * This function parses a string and tries to do a best guess at the contained
 * time information. Currently, it detects strings in the format "yyyy-mm-dd hh:mm:ss.000"
 * and posix time.
 */
48
void TimeStamp::guessFromString(std::string timestr, bool localTime)
Axel Auweter's avatar
Axel Auweter committed
49
50
{
  boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
51
  uint64_t tmp;
Axel Auweter's avatar
Axel Auweter committed
52
53
54
55
56
57
58

  /* First try to match it against a time string */
  try {
      boost::posix_time::ptime ts(boost::posix_time::time_from_string(timestr));
      if (ts != boost::posix_time::not_a_date_time) {
          boost::posix_time::time_duration diff = ts - epoch;
          raw = diff.total_nanoseconds();
59
60
61
          if (localTime) {
              convertFromLocal();
          }
Axel Auweter's avatar
Axel Auweter committed
62
63
64
65
66
67
68
          return;
      }
  }
  catch (std::exception& e) {
      /* Ignore on error */
  }

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  /*
   * Try to match it against a string containing "now".
   * Note that we ignore the localTime flag in this case since
   * we already get "now" in UTC.
   */
  if (timestr.find("now") != std::string::npos) {

      /* If the string is just "now"... */
      if ((timestr.compare("now") == 0) && (timestr.length() == 3)) {
          setNow();
          return;
      }

      /* If the string is of the form "now-X" */
      boost::regex d("now-[0-9]*d", boost::regex::extended);
      boost::regex h("now-[0-9]*h", boost::regex::extended);
      boost::regex m("now-[0-9]*m", boost::regex::extended);
      boost::regex s("now-[0-9]*s", boost::regex::extended);

      if (boost::regex_match(timestr, d)) {
          sscanf(timestr.c_str(), "now-%" PRIu64, &tmp);
          setNow();
          raw -= tmp * 24 * 60 * 60 * 1000 * 1000 * 1000;
          return;
      }
      if (boost::regex_match(timestr, h)) {
          sscanf(timestr.c_str(), "now-%" PRIu64, &tmp);
          setNow();
          raw -= tmp * 60 * 60 * 1000 * 1000 * 1000;
          return;
      }
      if (boost::regex_match(timestr, m)) {
          sscanf(timestr.c_str(), "now-%" PRIu64, &tmp);
          setNow();
103
          raw -= tmp * 60 * 1000 * 1000 * 1000;
104
105
106
107
108
109
110
111
112
113
          return;
      }
      if (boost::regex_match(timestr, s)) {
          sscanf(timestr.c_str(), "now-%" PRIu64, &tmp);
          setNow();
          raw -= tmp * 1000 * 1000 * 1000;
          return;
      }

      /* "now" keyword is in the timestamp but does not match one of the predefined formats */
114
      throw TimeStampConversionException();
115
116
  }

Axel Auweter's avatar
Axel Auweter committed
117
118
  /* Try to match it against a POSIX time */
  if (sscanf(timestr.c_str(), "%" PRIu64, &tmp) == 1) {
119
	  /* Checker whether it is a date before 2070-12-31 */
120
	  if (tmp < 31872923400ull) {                   // s
121
		raw = tmp * 1000 * 1000 * 1000;
122
	  } else if (tmp < 31872923400000ull) {         // ms
123
		raw = tmp * 1000 * 1000;
124
	  } else if (tmp < 31872923400000000ull) {      // ns
125
		raw = tmp * 1000;
126
	  } else {                                      // us
127
128
		raw = tmp;
	  }
129

Axel Auweter's avatar
Axel Auweter committed
130
131
132
  }

  /* Not successful - throw exception */
133
  throw TimeStampConversionException();
Axel Auweter's avatar
Axel Auweter committed
134
135
136
137
138
}

/**
 * This constructor is implemented by calling setNow().
 */
139
TimeStamp::TimeStamp()
Axel Auweter's avatar
Axel Auweter committed
140
141
142
143
144
145
146
{
  setNow();
}

/**
 * This constructor sets the time using the magic implemented in guessFromString.
 */
147
TimeStamp::TimeStamp(std::string ts, bool localTime)
Axel Auweter's avatar
Axel Auweter committed
148
{
149
  guessFromString(ts, localTime);
Axel Auweter's avatar
Axel Auweter committed
150
151
}

152
153
154
/**
 * This constructor sets the from a time_t struct.
 */
155
TimeStamp::TimeStamp(time_t ts)
156
157
158
159
160
161
162
163
{
  boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
  boost::posix_time::ptime t =  boost::posix_time::from_time_t(ts);
  boost::posix_time::time_duration diff = t - epoch;

  raw = diff.total_nanoseconds();
}

Axel Auweter's avatar
Axel Auweter committed
164
165
166
/**
 * Currently, the destructor doesn't need to do anything.
 */
167
TimeStamp::~TimeStamp()
Axel Auweter's avatar
Axel Auweter committed
168
169
170
171
172
173
174
{
}

/**
 * This function sets the value of raw to the nanoseconds since epoch
 * using some magic help of boost::posix_time.
 */
175
void TimeStamp::setNow(void)
Axel Auweter's avatar
Axel Auweter committed
176
177
178
179
180
181
182
183
{
  boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
  boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
  boost::posix_time::time_duration diff = now - epoch;

  raw = diff.total_nanoseconds();
}

184
/**
185
 * Treat the current value as local time and replace with the equivalent in UTC.
186
 */
187
void TimeStamp::convertFromLocal()
188
189
190
{
  /*
   * Unfortunately BOOST c_local_adjustor doesn't support local-to-utc conversion.
191
   * Therefore, we first check the offset of "raw" during utc-to-local conversion
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
   * and then apply this offset in the other direction.
   */

  /* Construct ptime object t from raw */
  boost::posix_time::ptime t(boost::gregorian::date(1970,1,1));
  t += boost::posix_time::nanoseconds(raw);

  /* Convert t to UTC */
  boost::posix_time::ptime t2 = local_adj::utc_to_local(t);

  /* Check the difference of the two times */
  boost::posix_time::time_duration diff = t - t2;

  /* Write back adjusted value to raw */
  raw += diff.total_nanoseconds();
}

/**
210
 * Treat the current value as UTC and replace with the equivalent in local time.
211
 */
212
void TimeStamp::convertToLocal()
213
214
215
216
217
218
219
220
221
222
223
224
225
226
{
  /* Construct ptime object t from raw */
  boost::posix_time::ptime t(boost::gregorian::date(1970,1,1));
  t += boost::posix_time::nanoseconds(raw);

  /* Convert t to Local */
  t = local_adj::utc_to_local(t);

  /* Write back to raw */
  boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
  boost::posix_time::time_duration diff = t - epoch;
  raw = diff.total_nanoseconds();
}

Axel Auweter's avatar
Axel Auweter committed
227
/**
228
 * Return the raw time value (nanoseconds since Unix epoch).
Axel Auweter's avatar
Axel Auweter committed
229
 */
230
uint64_t TimeStamp::getRaw(void) const
Axel Auweter's avatar
Axel Auweter committed
231
232
233
234
{
  return raw;
}

235
/**
236
 * Return the current value as string.
237
 */
238
std::string TimeStamp::getString(void) const
239
240
241
242
243
244
245
246
247
248
{
#ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
#error Needs nanoseconds support in boost.
#endif
  boost::posix_time::ptime t(boost::gregorian::date(1970,1,1));
  t += boost::posix_time::nanoseconds(raw);
  return boost::posix_time::to_iso_extended_string(t);
}


249
/**
250
 * Return the "weekstamp" of the current value.
251
 */
252
uint16_t TimeStamp::getWeekstamp(void) const
253
{
254
  uint16_t week = raw / 604800000000000;
255
256
  return week;
}
Axel Auweter's avatar
Axel Auweter committed
257