Doxygen
Loading...
Searching...
No Matches
datetime.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2022 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#include <cstdlib>
17#include <chrono>
18#include <memory>
19#include <array>
20#include <functional>
21
22#include "regex.h"
23#include "datetime.h"
24#include "config.h"
25#include "portable.h"
26#include "language.h"
27#include "message.h"
28#include "growbuf.h"
29
31{
32 QCString sourceDateEpoch = Portable::getenv("SOURCE_DATE_EPOCH");
33 if (!sourceDateEpoch.isEmpty()) // see https://reproducible-builds.org/specs/source-date-epoch/
34 {
35 bool ok = false;
36 uint64_t epoch = sourceDateEpoch.toUInt64(&ok);
37 if (!ok)
38 {
39 static bool warnedOnce=FALSE;
40 if (!warnedOnce)
41 {
42 warn_uncond("Environment variable SOURCE_DATE_EPOCH does not contain a valid number; value is '%s'\n",
43 qPrint(sourceDateEpoch));
44 warnedOnce=TRUE;
45 }
46 }
47 else // use given epoch value as current 'built' time
48 {
49 auto epoch_start = std::chrono::time_point<std::chrono::system_clock>{};
50 auto epoch_seconds = std::chrono::seconds(epoch);
51 auto build_time = epoch_start + epoch_seconds;
52 std::time_t time = std::chrono::system_clock::to_time_t(build_time);
53 return *gmtime(&time);
54 }
55 }
56
57 // return current local time
58 auto now = std::chrono::system_clock::now();
59 std::time_t time = std::chrono::system_clock::to_time_t(now);
60 return *localtime(&time);
61}
62
64{
65 auto current = getCurrentDateTime();
66 return theTranslator->trDateTime(current.tm_year + 1900,
67 current.tm_mon + 1,
68 current.tm_mday,
69 (current.tm_wday+6)%7+1, // map: Sun=0..Sat=6 to Mon=1..Sun=7
70 current.tm_hour,
71 current.tm_min,
72 current.tm_sec,
73 includeTime);
74}
75
77{
78 auto current = getCurrentDateTime();
79 return QCString().setNum(current.tm_year+1900);
80}
81
83{
84 const reg::Ex re;
85 int count;
86 int offset;
87 int format;
88};
89
90using TMFieldAssigner = std::function< void(std::tm &,int value) >;
91
93{
95 int minVal;
96 int maxVal;
97 const char *name;
98};
99
100static std::array g_specFormats
101{
102 // regular expression, num values, offset, format bits
103 SpecFormat{ std::string_view(R"((\d+)-(\d+)-(\d+)\s*(\d+):(\d+):(\d+))"), 6, 0, SF_Date|SF_Time|SF_Seconds }, // format 13-04-2015 12:34:56
104 SpecFormat{ std::string_view(R"((\d+)-(\d+)-(\d+)\s*(\d+):(\d+))"), 5, 0, SF_Date|SF_Time }, // format 13-04-2015 12:34
105 SpecFormat{ std::string_view(R"((\d+)-(\d+)-(\d+))"), 3, 0, SF_Date }, // format 13-04-2015
106 SpecFormat{ std::string_view(R"((\d+):(\d+):(\d+))"), 3, 3, SF_Time|SF_Seconds }, // format 12:34:56
107 SpecFormat{ std::string_view(R"((\d+):(\d+))"), 2, 3, SF_Time } // format 12:34
108};
109
110static std::array g_assignValues
111{
112 // assigner, minVal, maxVal, name
113 DateTimeField{ [](std::tm &tm,int value) { tm.tm_year = value-1900; }, 1900, 9999, "year" },
114 DateTimeField{ [](std::tm &tm,int value) { tm.tm_mon = value-1; }, 1, 12, "month" },
115 DateTimeField{ [](std::tm &tm,int value) { tm.tm_mday = value; }, 1, 31, "day" },
116 DateTimeField{ [](std::tm &tm,int value) { tm.tm_hour = value; }, 0, 23, "hour" },
117 DateTimeField{ [](std::tm &tm,int value) { tm.tm_min = value; }, 0, 59, "minute" },
118 DateTimeField{ [](std::tm &tm,int value) { tm.tm_sec = value; }, 0, 59, "second" }
119};
120
121static void determine_weekday( std::tm& tm )
122{
123 auto cpy = tm;
124 // there are some problems when the hr:min:sec are on 00:00:00 in determining the weekday
125 cpy.tm_hour = 12;
126 const auto as_time_t = std::mktime( &cpy ) ;
127 if (as_time_t != -1)
128 {
129 cpy = *std::localtime( &as_time_t ) ;
130 tm.tm_wday = cpy.tm_wday;
131 }
132}
133
134QCString dateTimeFromString(const QCString &spec,std::tm &dt,int &format)
135{
136 // for an empty spec field return the current date and time
137 dt = getCurrentDateTime();
138 if (spec.isEmpty())
139 {
140 format = SF_Date | SF_Time | SF_Seconds;
141 return QCString();
142 }
143
144 // find a matching pattern
145 std::string s = spec.str();
146 for (const auto &fmt : g_specFormats)
147 {
148 reg::Match m;
149 if (reg::match(s,m,fmt.re)) // match found
150 {
151 for (int i=0; i<fmt.count; i++)
152 {
153 int value = std::atoi(m[i+1].str().c_str());
154 const DateTimeField &dtf = g_assignValues[i+fmt.offset];
155 if (value<dtf.minVal || value>dtf.maxVal) // check if the value is in the expected range
156 {
157 return QCString().sprintf("value for %s is %d which is outside of the value range [%d..%d]",
158 dtf.name, value, dtf.minVal, dtf.maxVal);
159 }
160 dtf.assigner(dt,value);
161 }
162 format = fmt.format;
163 if (format&SF_Date) // if we have a date also determine the weekday
164 {
166 }
167 return QCString();
168 }
169 }
170
171 // no matching pattern found
172 return "invalid or non representable date/time argument";
173}
174
175QCString formatDateTime(const QCString &format,const std::tm &dt,int &formatUsed)
176{
177 formatUsed = 0;
178 auto getYear = [](const std::tm &dat) { return dat.tm_year+1900; };
179 auto getMonth = [](const std::tm &dat) { return dat.tm_mon+1; };
180 auto getDay = [](const std::tm &dat) { return dat.tm_mday; };
181 auto getDayOfWeek = [](const std::tm &dat) { return (dat.tm_wday+6)%7+1; };
182 GrowBuf growBuf;
183 char c = 0;
184 const char *p = format.data();
185 const char *fmt_zero = "%02d";
186 const char *fmt_nonzero = "%d";
187 const char *fmt_selected = nullptr;
188 if (p==nullptr) return QCString();
189 while ((c=*p++))
190 {
191 char nc = *p;
192 switch (c)
193 {
194 case '%':
195 fmt_selected = nc=='-' ? fmt_nonzero : fmt_zero; // %-H produces 1 and %H produces 01
196 if (nc=='-') nc=*++p; // skip over -
197 switch (nc)
198 {
199 case '%': growBuf.addChar('%'); break;
200 case 'y': growBuf.addInt(fmt_selected,getYear(dt)%100); formatUsed|=SF_Date; break;
201 case 'Y': growBuf.addInt("%d",getYear(dt)); formatUsed|=SF_Date; break;
202 case 'm': growBuf.addInt(fmt_selected,getMonth(dt)); formatUsed|=SF_Date; break;
203 case 'b': growBuf.addStr(theTranslator->trMonth(getMonth(dt),false,false)); formatUsed|=SF_Date; break;
204 case 'B': growBuf.addStr(theTranslator->trMonth(getMonth(dt),false,true)); formatUsed|=SF_Date; break;
205 case 'd': growBuf.addInt(fmt_selected,getDay(dt)); formatUsed|=SF_Date; break;
206 case 'u': growBuf.addInt("%d",getDayOfWeek(dt)); /* Monday = 1 ... Sunday = 7 */ formatUsed|=SF_Date; break;
207 case 'w': growBuf.addInt("%d",getDayOfWeek(dt)%7); /* Sunday = 0 ... Saturday = 6 */ formatUsed|=SF_Date; break;
208 case 'a': growBuf.addStr(theTranslator->trDayOfWeek(getDayOfWeek(dt),false,false)); formatUsed|=SF_Date; break;
209 case 'A': growBuf.addStr(theTranslator->trDayOfWeek(getDayOfWeek(dt),false,true)); formatUsed|=SF_Date; break;
210 case 'H': growBuf.addInt(fmt_selected,dt.tm_hour); formatUsed|=SF_Time; break;
211 case 'I': growBuf.addInt(fmt_selected,dt.tm_hour%12); formatUsed|=SF_Time; break;
212 case 'p': growBuf.addStr(theTranslator->trDayPeriod(dt.tm_hour>=12)); formatUsed|=SF_Time; break;
213 case 'M': growBuf.addInt(fmt_selected,dt.tm_min); formatUsed|=SF_Time; break;
214 case 'S': growBuf.addInt(fmt_selected,dt.tm_sec); formatUsed|=SF_Seconds; break;
215 default:
216 growBuf.addChar(c);
217 if (*(p-1)=='-') growBuf.addChar('-');
218 growBuf.addChar(nc);
219 break;
220 }
221 p++;
222 break;
223 default:
224 growBuf.addChar(c);
225 break;
226 }
227 }
228 growBuf.addChar(0);
229 return growBuf.get();
230}
231
Class representing a string buffer optimized for growing.
Definition growbuf.h:28
void addInt(const char *fmt, int value)
Definition growbuf.h:109
void addChar(char c)
Definition growbuf.h:69
void addStr(const QCString &s)
Definition growbuf.h:72
char * get()
Definition growbuf.h:114
This is an alternative implementation of QCString.
Definition qcstring.h:101
uint64_t toUInt64(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:356
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
const std::string & str() const
Definition qcstring.h:537
QCString & setNum(short n)
Definition qcstring.h:444
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
Class representing a regular expression.
Definition regex.h:39
Object representing the matching results.
Definition regex.h:153
QCString dateToString(DateTimeType includeTime)
Returns the current date, when includeTime is set also the time is provided.
Definition datetime.cpp:63
std::function< void(std::tm &, int value) > TMFieldAssigner
Definition datetime.cpp:90
QCString yearToString()
Returns the current year as a string.
Definition datetime.cpp:76
QCString formatDateTime(const QCString &format, const std::tm &dt, int &formatUsed)
Return a string representation for a given std::tm value that is formatted according to the pattern g...
Definition datetime.cpp:175
std::tm getCurrentDateTime()
Returns the filled in std::tm for the current date and time.
Definition datetime.cpp:30
static void determine_weekday(std::tm &tm)
Definition datetime.cpp:121
QCString dateTimeFromString(const QCString &spec, std::tm &dt, int &format)
Returns the filled in std::tm for a given string representing a date and/or time.
Definition datetime.cpp:134
static std::array g_assignValues
Definition datetime.cpp:111
static std::array g_specFormats
Definition datetime.cpp:101
DateTimeType
Definition datetime.h:38
constexpr int SF_Seconds
the seconds are presenting in the format string
Definition datetime.h:26
constexpr int SF_Date
Date and time related functions.
Definition datetime.h:24
constexpr int SF_Time
a time is presenting in the format string
Definition datetime.h:25
Translator * theTranslator
Definition language.cpp:71
#define warn_uncond(fmt,...)
Definition message.h:79
QCString getenv(const QCString &variable)
Definition portable.cpp:338
Definition trace.h:153
bool match(std::string_view str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition regex.cpp:759
Portable versions of functions that are platform dependent.
const char * qPrint(const char *s)
Definition qcstring.h:672
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
TMFieldAssigner assigner
Definition datetime.cpp:94
const char * name
Definition datetime.cpp:97
const reg::Ex re
Definition datetime.cpp:84