QGIS API Documentation 3.29.0-Master (8c80f25a4f)
qgsinterval.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsinterval.cpp
3 ---------------
4 Date : May 2016
5 Copyright : (C) 2016 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsinterval.h"
17
18#include <QString>
19#include <QStringList>
20#include <QMap>
21#include <QObject>
22#include <QDebug>
23#include <QDateTime>
24#include <QRegularExpression>
25
26/***************************************************************************
27 * This class is considered CRITICAL and any change MUST be accompanied with
28 * full unit tests in test_qgsinterval.py.
29 * See details in QEP #17
30 ****************************************************************************/
31
32QgsInterval::QgsInterval( double seconds )
33 : mSeconds( seconds )
34 , mValid( true )
35 , mOriginalDuration( seconds )
36 , mOriginalUnit( QgsUnitTypes::TemporalSeconds )
37{
38}
39
40QgsInterval::QgsInterval( std::chrono::milliseconds milliseconds )
41 : mSeconds( static_cast<double>( milliseconds.count() ) / 1000.0 )
42 , mValid( true )
43 , mOriginalDuration( static_cast<double>( milliseconds.count() ) )
44 , mOriginalUnit( QgsUnitTypes::TemporalMilliseconds )
45{
46}
47
49 : mSeconds( duration * QgsUnitTypes::fromUnitToUnitFactor( unit, QgsUnitTypes::TemporalSeconds ) )
50 , mValid( true )
51 , mOriginalDuration( duration )
52 , mOriginalUnit( unit )
53{
54}
55
56QgsInterval::QgsInterval( double years, double months, double weeks, double days, double hours, double minutes, double seconds )
57 : mSeconds( years * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalYears, QgsUnitTypes::TemporalSeconds )
58 + months * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalMonths, QgsUnitTypes::TemporalSeconds )
59 + weeks * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalWeeks, QgsUnitTypes::TemporalSeconds )
60 + days * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalDays, QgsUnitTypes::TemporalSeconds )
61 + hours * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalHours, QgsUnitTypes::TemporalSeconds )
62 + minutes * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalMinutes, QgsUnitTypes::TemporalSeconds )
63 + seconds )
64 , mValid( true )
65{
66 if ( years && !months && !weeks && !days && !hours && !minutes && !seconds )
67 {
68 mOriginalDuration = years;
69 mOriginalUnit = QgsUnitTypes::TemporalYears;
70 }
71 else if ( !years && months && !weeks && !days && !hours && !minutes && !seconds )
72 {
73 mOriginalDuration = months;
74 mOriginalUnit = QgsUnitTypes::TemporalMonths;
75 }
76 else if ( !years && !months && weeks && !days && !hours && !minutes && !seconds )
77 {
78 mOriginalDuration = weeks;
79 mOriginalUnit = QgsUnitTypes::TemporalWeeks;
80 }
81 else if ( !years && !months && !weeks && days && !hours && !minutes && !seconds )
82 {
83 mOriginalDuration = days;
84 mOriginalUnit = QgsUnitTypes::TemporalDays;
85 }
86 else if ( !years && !months && !weeks && !days && hours && !minutes && !seconds )
87 {
88 mOriginalDuration = hours;
89 mOriginalUnit = QgsUnitTypes::TemporalHours;
90 }
91 else if ( !years && !months && !weeks && !days && !hours && minutes && !seconds )
92 {
93 mOriginalDuration = minutes;
94 mOriginalUnit = QgsUnitTypes::TemporalMinutes;
95 }
96 else if ( !years && !months && !weeks && !days && !hours && !minutes && seconds )
97 {
98 mOriginalDuration = seconds;
99 mOriginalUnit = QgsUnitTypes::TemporalSeconds;
100 }
101 else if ( !years && !months && !weeks && !days && !hours && !minutes && !seconds )
102 {
103 mOriginalDuration = 0;
104 mOriginalUnit = QgsUnitTypes::TemporalSeconds;
105 }
106 else
107 {
108 mOriginalUnit = QgsUnitTypes::TemporalUnknownUnit;
109 }
110}
111
112double QgsInterval::years() const
113{
114 if ( mOriginalUnit == QgsUnitTypes::TemporalYears )
115 return mOriginalDuration;
116
117 return mSeconds / YEARS;
118}
119
120void QgsInterval::setYears( double years )
121{
122 mSeconds = years * YEARS;
123 mValid = true;
124 mOriginalDuration = years;
125 mOriginalUnit = QgsUnitTypes::TemporalYears;
126}
127
129{
130 if ( mOriginalUnit == QgsUnitTypes::TemporalMonths )
131 return mOriginalDuration;
132
133 return mSeconds / MONTHS;
134}
135
136void QgsInterval::setMonths( double months )
137{
138 mSeconds = months * MONTHS;
139 mValid = true;
140 mOriginalDuration = months;
141 mOriginalUnit = QgsUnitTypes::TemporalMonths;
142}
143
144double QgsInterval::weeks() const
145{
146 if ( mOriginalUnit == QgsUnitTypes::TemporalWeeks )
147 return mOriginalDuration;
148
149 return mSeconds / WEEKS;
150}
151
152
153void QgsInterval::setWeeks( double weeks )
154{
155 mSeconds = weeks * WEEKS;
156 mValid = true;
157 mOriginalDuration = weeks;
158 mOriginalUnit = QgsUnitTypes::TemporalWeeks;
159}
160
161double QgsInterval::days() const
162{
163 if ( mOriginalUnit == QgsUnitTypes::TemporalDays )
164 return mOriginalDuration;
165
166 return mSeconds / DAY;
167}
168
169
170void QgsInterval::setDays( double days )
171{
172 mSeconds = days * DAY;
173 mValid = true;
174 mOriginalDuration = days;
175 mOriginalUnit = QgsUnitTypes::TemporalDays;
176}
177
178double QgsInterval::hours() const
179{
180 if ( mOriginalUnit == QgsUnitTypes::TemporalHours )
181 return mOriginalDuration;
182
183 return mSeconds / HOUR;
184}
185
186
187void QgsInterval::setHours( double hours )
188{
189 mSeconds = hours * HOUR;
190 mValid = true;
191 mOriginalDuration = hours;
192 mOriginalUnit = QgsUnitTypes::TemporalHours;
193}
194
196{
197 if ( mOriginalUnit == QgsUnitTypes::TemporalMinutes )
198 return mOriginalDuration;
199
200 return mSeconds / MINUTE;
201}
202
203void QgsInterval::setMinutes( double minutes )
204{
205 mSeconds = minutes * MINUTE;
206 mValid = true;
207 mOriginalDuration = minutes;
208 mOriginalUnit = QgsUnitTypes::TemporalMinutes;
209}
210
211void QgsInterval::setSeconds( double seconds )
212{
213 mSeconds = seconds;
214 mValid = true;
215 mOriginalDuration = seconds;
216 mOriginalUnit = QgsUnitTypes::TemporalSeconds;
217}
218
219QgsInterval QgsInterval::fromString( const QString &string )
220{
221 double seconds = 0;
222 const thread_local QRegularExpression rx( "([-+]?\\d*\\.?\\d+\\s+\\S+)", QRegularExpression::CaseInsensitiveOption );
223 const thread_local QRegularExpression rxtime( ".* \\d{1,2}(:)\\d{1,2}(:)\\d{1,2}.*", QRegularExpression::CaseInsensitiveOption );
224
225 const QRegularExpressionMatch matchtime = rxtime.match( string );
226 QString modedString = QString( string );
227 if ( matchtime.hasMatch() ) //some part of the string contains 00:00:00 style duration
228 {
229 // Get the second occurrence of : (minutes)
230 modedString.replace( matchtime.capturedStart( 2 ), 1, " minutes " );
231 // Get the first occurrence of : (hours)
232 modedString.replace( matchtime.capturedStart( 1 ), 1, " hours " );
233 modedString.append( " seconds" );
234 }
235
236 QStringList list;
237 int pos = 0;
238 QRegularExpressionMatch match = rx.match( modedString );
239 while ( match.hasMatch() )
240 {
241 list << match.captured( 1 );
242 pos = match.capturedStart() + match.capturedLength();
243 match = rx.match( modedString, pos );
244 }
245
246 const thread_local QMap<int, QStringList> map{{
247 {1, QStringList() << QStringLiteral( "second" ) << QStringLiteral( "seconds" ) << QObject::tr( "second|seconds", "list of words separated by | which reference years" ).split( '|' )},
248 { 0 + MINUTE, QStringList() << QStringLiteral( "minute" ) << QStringLiteral( "minutes" ) << QObject::tr( "minute|minutes", "list of words separated by | which reference minutes" ).split( '|' ) },
249 {0 + HOUR, QStringList() << QStringLiteral( "hour" ) << QStringLiteral( "hours" ) << QObject::tr( "hour|hours", "list of words separated by | which reference minutes hours" ).split( '|' )},
250 {0 + DAY, QStringList() << QStringLiteral( "day" ) << QStringLiteral( "days" ) << QObject::tr( "day|days", "list of words separated by | which reference days" ).split( '|' )},
251 {0 + WEEKS, QStringList() << QStringLiteral( "week" ) << QStringLiteral( "weeks" ) << QObject::tr( "week|weeks", "wordlist separated by | which reference weeks" ).split( '|' )},
252 {0 + MONTHS, QStringList() << QStringLiteral( "month" ) << QStringLiteral( "months" ) << QStringLiteral( "mon" ) << QObject::tr( "month|months|mon", "list of words separated by | which reference months" ).split( '|' )},
253 {0 + YEARS, QStringList() << QStringLiteral( "year" ) << QStringLiteral( "years" ) << QObject::tr( "year|years", "list of words separated by | which reference years" ).split( '|' )},
254 }};
255
256 const thread_local QRegularExpression splitRx( "\\s+" );
257
258 for ( const QString &match : std::as_const( list ) )
259 {
260 const QStringList split = match.split( splitRx );
261 bool ok;
262 const double value = split.at( 0 ).toDouble( &ok );
263 if ( !ok )
264 {
265 continue;
266 }
267
268 bool matched = false;
269 QMap<int, QStringList>::const_iterator it = map.constBegin();
270 for ( ; it != map.constEnd(); ++it )
271 {
272 const int duration = it.key();
273 const QStringList durationIdentifiers = it.value();
274 for ( const QString &identifier : durationIdentifiers )
275 {
276 if ( match.contains( identifier, Qt::CaseInsensitive ) )
277 {
278 matched = true;
279 break;
280 }
281 }
282
283 if ( matched )
284 {
285 seconds += value * duration;
286 break;
287 }
288 }
289 }
290
291 // If we can't parse the string at all then we just return invalid
292 if ( seconds == 0 )
293 return QgsInterval();
294
295 return QgsInterval( seconds );
296}
297
298QDebug operator<<( QDebug dbg, const QgsInterval &interval )
299{
300 if ( !interval.isValid() )
301 dbg.nospace() << "QgsInterval()";
302 else
303 dbg.nospace() << "QgsInterval(" << interval.seconds() << ")";
304 return dbg.maybeSpace();
305}
306
307#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
308
309QgsInterval operator-( const QDateTime &dt1, const QDateTime &dt2 )
310{
311 const qint64 mSeconds = dt2.msecsTo( dt1 );
312 return QgsInterval( mSeconds / 1000.0 );
313}
314
315#endif
316
317QDateTime operator+( const QDateTime &start, const QgsInterval &interval )
318{
319 return start.addMSecs( static_cast<qint64>( interval.seconds() * 1000.0 ) );
320}
321
322QgsInterval operator-( QDate date1, QDate date2 )
323{
324 const qint64 seconds = static_cast< qint64 >( date2.daysTo( date1 ) ) * 24 * 60 * 60;
325 return QgsInterval( seconds );
326}
327
328QgsInterval operator-( QTime time1, QTime time2 )
329{
330 const qint64 mSeconds = time2.msecsTo( time1 );
331 return QgsInterval( mSeconds / 1000.0 );
332}
333
A representation of the interval between two datetime values.
Definition: qgsinterval.h:43
static const int MINUTE
Seconds per minute.
Definition: qgsinterval.h:59
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:262
double days() const
Returns the interval duration in days.
void setMinutes(double minutes)
Sets the interval duration in minutes.
void setWeeks(double weeks)
Sets the interval duration in weeks.
QgsInterval()=default
Default constructor for QgsInterval.
double weeks() const
Returns the interval duration in weeks.
static const int MONTHS
Seconds per month, based on 30 day month.
Definition: qgsinterval.h:51
double months() const
Returns the interval duration in months (based on a 30 day month).
static QgsInterval fromString(const QString &string)
Converts a string to an interval.
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:243
double years() const
Returns the interval duration in years (based on an average year length)
static const int HOUR
Seconds per hour.
Definition: qgsinterval.h:57
static const int WEEKS
Seconds per week.
Definition: qgsinterval.h:53
static const int DAY
Seconds per day.
Definition: qgsinterval.h:55
double hours() const
Returns the interval duration in hours.
void setHours(double hours)
Sets the interval duration in hours.
static const int YEARS
Seconds per year (average)
Definition: qgsinterval.h:49
void setYears(double years)
Sets the interval duration in years.
void setSeconds(double seconds)
Sets the interval duration in seconds.
void setDays(double days)
Sets the interval duration in days.
double minutes() const
Returns the interval duration in minutes.
void setMonths(double months)
Sets the interval duration in months.
Helper functions for various unit types.
Definition: qgsunittypes.h:39
TemporalUnit
Temporal units.
Definition: qgsunittypes.h:150
@ TemporalMonths
Months.
Definition: qgsunittypes.h:157
@ TemporalUnknownUnit
Unknown time unit.
Definition: qgsunittypes.h:162
@ TemporalWeeks
Weeks.
Definition: qgsunittypes.h:156
@ TemporalDays
Days.
Definition: qgsunittypes.h:155
@ TemporalSeconds
Seconds.
Definition: qgsunittypes.h:152
@ TemporalMinutes
Minutes.
Definition: qgsunittypes.h:153
@ TemporalYears
Years.
Definition: qgsunittypes.h:158
@ TemporalHours
Hours.
Definition: qgsunittypes.h:154
QDebug operator<<(QDebug dbg, const QgsInterval &interval)
Debug string representation of interval.
QgsInterval operator-(QDate date1, QDate date2)
Returns the interval between two dates.
QDateTime operator+(const QDateTime &start, const QgsInterval &interval)
Adds an interval to a datetime.