QGIS API Documentation  3.21.0-Master (5b68dc587e)
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 
32 QgsInterval::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 
48 QgsInterval::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 
104 double QgsInterval::years() const
105 {
106  if ( mOriginalUnit == QgsUnitTypes::TemporalYears )
107  return mOriginalDuration;
108 
109  return mSeconds / YEARS;
110 }
111 
112 void QgsInterval::setYears( double years )
113 {
114  mSeconds = years * YEARS;
115  mValid = true;
116  mOriginalDuration = years;
117  mOriginalUnit = QgsUnitTypes::TemporalYears;
118 }
119 
120 double QgsInterval::months() const
121 {
122  if ( mOriginalUnit == QgsUnitTypes::TemporalMonths )
123  return mOriginalDuration;
124 
125  return mSeconds / MONTHS;
126 }
127 
128 void QgsInterval::setMonths( double months )
129 {
130  mSeconds = months * MONTHS;
131  mValid = true;
132  mOriginalDuration = months;
133  mOriginalUnit = QgsUnitTypes::TemporalMonths;
134 }
135 
136 double QgsInterval::weeks() const
137 {
138  if ( mOriginalUnit == QgsUnitTypes::TemporalWeeks )
139  return mOriginalDuration;
140 
141  return mSeconds / WEEKS;
142 }
143 
144 
145 void QgsInterval::setWeeks( double weeks )
146 {
147  mSeconds = weeks * WEEKS;
148  mValid = true;
149  mOriginalDuration = weeks;
150  mOriginalUnit = QgsUnitTypes::TemporalWeeks;
151 }
152 
153 double QgsInterval::days() const
154 {
155  if ( mOriginalUnit == QgsUnitTypes::TemporalDays )
156  return mOriginalDuration;
157 
158  return mSeconds / DAY;
159 }
160 
161 
162 void QgsInterval::setDays( double days )
163 {
164  mSeconds = days * DAY;
165  mValid = true;
166  mOriginalDuration = days;
167  mOriginalUnit = QgsUnitTypes::TemporalDays;
168 }
169 
170 double QgsInterval::hours() const
171 {
172  if ( mOriginalUnit == QgsUnitTypes::TemporalHours )
173  return mOriginalDuration;
174 
175  return mSeconds / HOUR;
176 }
177 
178 
179 void QgsInterval::setHours( double hours )
180 {
181  mSeconds = hours * HOUR;
182  mValid = true;
183  mOriginalDuration = hours;
184  mOriginalUnit = QgsUnitTypes::TemporalHours;
185 }
186 
187 double QgsInterval::minutes() const
188 {
189  if ( mOriginalUnit == QgsUnitTypes::TemporalMinutes )
190  return mOriginalDuration;
191 
192  return mSeconds / MINUTE;
193 }
194 
195 void QgsInterval::setMinutes( double minutes )
196 {
197  mSeconds = minutes * MINUTE;
198  mValid = true;
199  mOriginalDuration = minutes;
200  mOriginalUnit = QgsUnitTypes::TemporalMinutes;
201 }
202 
203 void QgsInterval::setSeconds( double seconds )
204 {
205  mSeconds = seconds;
206  mValid = true;
207  mOriginalDuration = seconds;
208  mOriginalUnit = QgsUnitTypes::TemporalSeconds;
209 }
210 
211 QgsInterval QgsInterval::fromString( const QString &string )
212 {
213  double seconds = 0;
214  const thread_local QRegularExpression rx( "([-+]?\\d*\\.?\\d+\\s+\\S+)", QRegularExpression::CaseInsensitiveOption );
215  QStringList list;
216  int pos = 0;
217  QRegularExpressionMatch match = rx.match( string );
218  while ( match.hasMatch() )
219  {
220  list << match.captured( 1 );
221  pos = match.capturedStart() + match.capturedLength();
222  match = rx.match( string, pos );
223  }
224 
225  QMap<int, QStringList> map;
226  map.insert( 1, QStringList() << QStringLiteral( "second" ) << QStringLiteral( "seconds" ) << QObject::tr( "second|seconds", "list of words separated by | which reference years" ).split( '|' ) );
227  map.insert( 0 + MINUTE, QStringList() << QStringLiteral( "minute" ) << QStringLiteral( "minutes" ) << QObject::tr( "minute|minutes", "list of words separated by | which reference minutes" ).split( '|' ) );
228  map.insert( 0 + HOUR, QStringList() << QStringLiteral( "hour" ) << QStringLiteral( "hours" ) << QObject::tr( "hour|hours", "list of words separated by | which reference minutes hours" ).split( '|' ) );
229  map.insert( 0 + DAY, QStringList() << QStringLiteral( "day" ) << QStringLiteral( "days" ) << QObject::tr( "day|days", "list of words separated by | which reference days" ).split( '|' ) );
230  map.insert( 0 + WEEKS, QStringList() << QStringLiteral( "week" ) << QStringLiteral( "weeks" ) << QObject::tr( "week|weeks", "wordlist separated by | which reference weeks" ).split( '|' ) );
231  map.insert( 0 + MONTHS, QStringList() << QStringLiteral( "month" ) << QStringLiteral( "months" ) << QObject::tr( "month|months", "list of words separated by | which reference months" ).split( '|' ) );
232  map.insert( 0 + YEARS, QStringList() << QStringLiteral( "year" ) << QStringLiteral( "years" ) << QObject::tr( "year|years", "list of words separated by | which reference years" ).split( '|' ) );
233 
234  const auto constList = list;
235  for ( const QString &match : constList )
236  {
237  const thread_local QRegularExpression splitRx( "\\s+" );
238  const QStringList split = match.split( splitRx );
239  bool ok;
240  const double value = split.at( 0 ).toDouble( &ok );
241  if ( !ok )
242  {
243  continue;
244  }
245 
246  bool matched = false;
247  QMap<int, QStringList>::const_iterator it = map.constBegin();
248  for ( ; it != map.constEnd(); ++it )
249  {
250  const int duration = it.key();
251  const auto constValue = it.value();
252  for ( const QString &name : constValue )
253  {
254  if ( match.contains( name, Qt::CaseInsensitive ) )
255  {
256  matched = true;
257  break;
258  }
259  }
260 
261  if ( matched )
262  {
263  seconds += value * duration;
264  break;
265  }
266  }
267  }
268 
269  // If we can't parse the string at all then we just return invalid
270  if ( seconds == 0 )
271  return QgsInterval();
272 
273  return QgsInterval( seconds );
274 }
275 
276 QDebug operator<<( QDebug dbg, const QgsInterval &interval )
277 {
278  if ( !interval.isValid() )
279  dbg.nospace() << "QgsInterval()";
280  else
281  dbg.nospace() << "QgsInterval(" << interval.seconds() << ")";
282  return dbg.maybeSpace();
283 }
284 
285 QgsInterval operator-( const QDateTime &dt1, const QDateTime &dt2 )
286 {
287  const qint64 mSeconds = dt2.msecsTo( dt1 );
288  return QgsInterval( mSeconds / 1000.0 );
289 }
290 
291 QDateTime operator+( const QDateTime &start, const QgsInterval &interval )
292 {
293  return start.addMSecs( static_cast<qint64>( interval.seconds() * 1000.0 ) );
294 }
295 
296 QgsInterval operator-( QDate date1, QDate date2 )
297 {
298  const qint64 seconds = static_cast< qint64 >( date2.daysTo( date1 ) ) * 24 * 60 * 60;
299  return QgsInterval( seconds );
300 }
301 
302 QgsInterval operator-( QTime time1, QTime time2 )
303 {
304  const qint64 mSeconds = time2.msecsTo( time1 );
305  return QgsInterval( mSeconds / 1000.0 );
306 }
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.