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