QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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
41 : mSeconds( duration * QgsUnitTypes::fromUnitToUnitFactor( unit, QgsUnitTypes::TemporalSeconds ) )
42 , mValid( true )
43 , mOriginalDuration( duration )
44 , mOriginalUnit( unit )
45{
46}
47
48QgsInterval::QgsInterval( double years, double months, double weeks, double days, double hours, double minutes, double seconds )
49 : mSeconds( years * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalYears, QgsUnitTypes::TemporalSeconds )
50 + months * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalMonths, QgsUnitTypes::TemporalSeconds )
51 + weeks * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalWeeks, QgsUnitTypes::TemporalSeconds )
52 + days * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalDays, QgsUnitTypes::TemporalSeconds )
53 + hours * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalHours, QgsUnitTypes::TemporalSeconds )
54 + minutes * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalMinutes, QgsUnitTypes::TemporalSeconds )
55 + seconds )
56 , mValid( true )
57{
58 if ( years && !months && !weeks && !days && !hours && !minutes && !seconds )
59 {
60 mOriginalDuration = years;
61 mOriginalUnit = QgsUnitTypes::TemporalYears;
62 }
63 else if ( !years && months && !weeks && !days && !hours && !minutes && !seconds )
64 {
65 mOriginalDuration = months;
66 mOriginalUnit = QgsUnitTypes::TemporalMonths;
67 }
68 else if ( !years && !months && weeks && !days && !hours && !minutes && !seconds )
69 {
70 mOriginalDuration = weeks;
71 mOriginalUnit = QgsUnitTypes::TemporalWeeks;
72 }
73 else if ( !years && !months && !weeks && days && !hours && !minutes && !seconds )
74 {
75 mOriginalDuration = days;
76 mOriginalUnit = QgsUnitTypes::TemporalDays;
77 }
78 else if ( !years && !months && !weeks && !days && hours && !minutes && !seconds )
79 {
80 mOriginalDuration = hours;
81 mOriginalUnit = QgsUnitTypes::TemporalHours;
82 }
83 else if ( !years && !months && !weeks && !days && !hours && minutes && !seconds )
84 {
85 mOriginalDuration = minutes;
86 mOriginalUnit = QgsUnitTypes::TemporalMinutes;
87 }
88 else if ( !years && !months && !weeks && !days && !hours && !minutes && seconds )
89 {
90 mOriginalDuration = seconds;
91 mOriginalUnit = QgsUnitTypes::TemporalSeconds;
92 }
93 else if ( !years && !months && !weeks && !days && !hours && !minutes && !seconds )
94 {
95 mOriginalDuration = 0;
96 mOriginalUnit = QgsUnitTypes::TemporalSeconds;
97 }
98 else
99 {
100 mOriginalUnit = QgsUnitTypes::TemporalUnknownUnit;
101 }
102}
103
104double QgsInterval::years() const
105{
106 if ( mOriginalUnit == QgsUnitTypes::TemporalYears )
107 return mOriginalDuration;
108
109 return mSeconds / YEARS;
110}
111
112void QgsInterval::setYears( double years )
113{
114 mSeconds = years * YEARS;
115 mValid = true;
116 mOriginalDuration = years;
117 mOriginalUnit = QgsUnitTypes::TemporalYears;
118}
119
121{
122 if ( mOriginalUnit == QgsUnitTypes::TemporalMonths )
123 return mOriginalDuration;
124
125 return mSeconds / MONTHS;
126}
127
128void QgsInterval::setMonths( double months )
129{
130 mSeconds = months * MONTHS;
131 mValid = true;
132 mOriginalDuration = months;
133 mOriginalUnit = QgsUnitTypes::TemporalMonths;
134}
135
136double QgsInterval::weeks() const
137{
138 if ( mOriginalUnit == QgsUnitTypes::TemporalWeeks )
139 return mOriginalDuration;
140
141 return mSeconds / WEEKS;
142}
143
144
145void QgsInterval::setWeeks( double weeks )
146{
147 mSeconds = weeks * WEEKS;
148 mValid = true;
149 mOriginalDuration = weeks;
150 mOriginalUnit = QgsUnitTypes::TemporalWeeks;
151}
152
153double QgsInterval::days() const
154{
155 if ( mOriginalUnit == QgsUnitTypes::TemporalDays )
156 return mOriginalDuration;
157
158 return mSeconds / DAY;
159}
160
161
162void QgsInterval::setDays( double days )
163{
164 mSeconds = days * DAY;
165 mValid = true;
166 mOriginalDuration = days;
167 mOriginalUnit = QgsUnitTypes::TemporalDays;
168}
169
170double QgsInterval::hours() const
171{
172 if ( mOriginalUnit == QgsUnitTypes::TemporalHours )
173 return mOriginalDuration;
174
175 return mSeconds / HOUR;
176}
177
178
179void QgsInterval::setHours( double hours )
180{
181 mSeconds = hours * HOUR;
182 mValid = true;
183 mOriginalDuration = hours;
184 mOriginalUnit = QgsUnitTypes::TemporalHours;
185}
186
188{
189 if ( mOriginalUnit == QgsUnitTypes::TemporalMinutes )
190 return mOriginalDuration;
191
192 return mSeconds / MINUTE;
193}
194
195void QgsInterval::setMinutes( double minutes )
196{
197 mSeconds = minutes * MINUTE;
198 mValid = true;
199 mOriginalDuration = minutes;
200 mOriginalUnit = QgsUnitTypes::TemporalMinutes;
201}
202
203void QgsInterval::setSeconds( double seconds )
204{
205 mSeconds = seconds;
206 mValid = true;
207 mOriginalDuration = seconds;
208 mOriginalUnit = QgsUnitTypes::TemporalSeconds;
209}
210
211QgsInterval QgsInterval::fromString( const QString &string )
212{
213 double seconds = 0;
214 const thread_local QRegularExpression rx( "([-+]?\\d*\\.?\\d+\\s+\\S+)", QRegularExpression::CaseInsensitiveOption );
215 const thread_local QRegularExpression rxtime( ".* \\d{1,2}(:)\\d{1,2}(:)\\d{1,2}.*", QRegularExpression::CaseInsensitiveOption );
216
217 const QRegularExpressionMatch matchtime = rxtime.match( string );
218 QString modedString = QString( string );
219 if ( matchtime.hasMatch() ) //some part of the string contains 00:00:00 style duration
220 {
221 // Get the second occurrence of : (minutes)
222 modedString.replace( matchtime.capturedStart( 2 ), 1, " minutes " );
223 // Get the first occurrence of : (hours)
224 modedString.replace( matchtime.capturedStart( 1 ), 1, " hours " );
225 modedString.append( " seconds" );
226 }
227
228 QStringList list;
229 int pos = 0;
230 QRegularExpressionMatch match = rx.match( modedString );
231 while ( match.hasMatch() )
232 {
233 list << match.captured( 1 );
234 pos = match.capturedStart() + match.capturedLength();
235 match = rx.match( modedString, pos );
236 }
237
238 const thread_local QMap<int, QStringList> map{{
239 {1, QStringList() << QStringLiteral( "second" ) << QStringLiteral( "seconds" ) << QObject::tr( "second|seconds", "list of words separated by | which reference years" ).split( '|' )},
240 { 0 + MINUTE, QStringList() << QStringLiteral( "minute" ) << QStringLiteral( "minutes" ) << QObject::tr( "minute|minutes", "list of words separated by | which reference minutes" ).split( '|' ) },
241 {0 + HOUR, QStringList() << QStringLiteral( "hour" ) << QStringLiteral( "hours" ) << QObject::tr( "hour|hours", "list of words separated by | which reference minutes hours" ).split( '|' )},
242 {0 + DAY, QStringList() << QStringLiteral( "day" ) << QStringLiteral( "days" ) << QObject::tr( "day|days", "list of words separated by | which reference days" ).split( '|' )},
243 {0 + WEEKS, QStringList() << QStringLiteral( "week" ) << QStringLiteral( "weeks" ) << QObject::tr( "week|weeks", "wordlist separated by | which reference weeks" ).split( '|' )},
244 {0 + MONTHS, QStringList() << QStringLiteral( "month" ) << QStringLiteral( "months" ) << QStringLiteral( "mon" ) << QObject::tr( "month|months|mon", "list of words separated by | which reference months" ).split( '|' )},
245 {0 + YEARS, QStringList() << QStringLiteral( "year" ) << QStringLiteral( "years" ) << QObject::tr( "year|years", "list of words separated by | which reference years" ).split( '|' )},
246 }};
247
248 const thread_local QRegularExpression splitRx( "\\s+" );
249
250 for ( const QString &match : std::as_const( list ) )
251 {
252 const QStringList split = match.split( splitRx );
253 bool ok;
254 const double value = split.at( 0 ).toDouble( &ok );
255 if ( !ok )
256 {
257 continue;
258 }
259
260 bool matched = false;
261 QMap<int, QStringList>::const_iterator it = map.constBegin();
262 for ( ; it != map.constEnd(); ++it )
263 {
264 const int duration = it.key();
265 const QStringList durationIdentifiers = it.value();
266 for ( const QString &identifier : durationIdentifiers )
267 {
268 if ( match.contains( identifier, Qt::CaseInsensitive ) )
269 {
270 matched = true;
271 break;
272 }
273 }
274
275 if ( matched )
276 {
277 seconds += value * duration;
278 break;
279 }
280 }
281 }
282
283 // If we can't parse the string at all then we just return invalid
284 if ( seconds == 0 )
285 return QgsInterval();
286
287 return QgsInterval( seconds );
288}
289
290QDebug operator<<( QDebug dbg, const QgsInterval &interval )
291{
292 if ( !interval.isValid() )
293 dbg.nospace() << "QgsInterval()";
294 else
295 dbg.nospace() << "QgsInterval(" << interval.seconds() << ")";
296 return dbg.maybeSpace();
297}
298
299QgsInterval operator-( const QDateTime &dt1, const QDateTime &dt2 )
300{
301 const qint64 mSeconds = dt2.msecsTo( dt1 );
302 return QgsInterval( mSeconds / 1000.0 );
303}
304
305QDateTime operator+( const QDateTime &start, const QgsInterval &interval )
306{
307 return start.addMSecs( static_cast<qint64>( interval.seconds() * 1000.0 ) );
308}
309
310QgsInterval operator-( QDate date1, QDate date2 )
311{
312 const qint64 seconds = static_cast< qint64 >( date2.daysTo( date1 ) ) * 24 * 60 * 60;
313 return QgsInterval( seconds );
314}
315
316QgsInterval operator-( QTime time1, QTime time2 )
317{
318 const qint64 mSeconds = time2.msecsTo( time1 );
319 return QgsInterval( mSeconds / 1000.0 );
320}
A representation of the interval between two datetime values.
Definition: qgsinterval.h:42
static const int MINUTE
Seconds per minute.
Definition: qgsinterval.h:58
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:255
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:50
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:236
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:56
static const int WEEKS
Seconds per week.
Definition: qgsinterval.h:52
static const int DAY
Seconds per day.
Definition: qgsinterval.h:54
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:48
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-(const QDateTime &dt1, const QDateTime &dt2)
Returns the interval between two datetimes.
QDateTime operator+(const QDateTime &start, const QgsInterval &interval)
Adds an interval to a datetime.