qwt_date.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_date.h"
11 #include "qwt_math.h"
12 
13 #include <qdebug.h>
14 #include <qlocale.h>
15 
16 #include <limits>
17 
18 #if QT_VERSION >= 0x050000
19 
20 typedef qint64 QwtJulianDay;
21 static const QwtJulianDay minJulianDayD = Q_INT64_C( -784350574879 );
22 static const QwtJulianDay maxJulianDayD = Q_INT64_C( 784354017364 );
23 
24 #else
25 
26 // QDate stores the Julian day as unsigned int, but
27 // there is QDate::fromJulianDay( int ). That's why
28 // we have the range [ 1, INT_MAX ]
29 
30 typedef int QwtJulianDay;
31 static const QwtJulianDay minJulianDayD = 1;
33 
34 #endif
35 
36 static QString qwtExpandedFormat( const QString & format,
37  const QDateTime &dateTime, QwtDate::Week0Type week0Type )
38 {
39  const int week = QwtDate::weekNumber( dateTime.date(), week0Type );
40 
41  QString weekNo;
42  weekNo.setNum( week );
43 
44  QString weekNoWW;
45  if ( weekNo.length() == 1 )
46  weekNoWW += QLatin1Char( '0' );
47 
48  weekNoWW += weekNo;
49 
50  QString fmt = format;
51  fmt.replace( QLatin1String( "ww" ), weekNoWW );
52  fmt.replace( QLatin1Char( 'w' ), weekNo );
53 
54  if ( week == 1 && dateTime.date().month() != 1 )
55  {
56  // in case of week 1, we might need to increment the year
57 
58  QLatin1String s_yyyy( "yyyy" );
59  QLatin1String s_yy( "yy" );
60 
61  // week 1 might start in the previous year
62 
63  bool doReplaceYear = fmt.contains( s_yy );
64 
65  if ( doReplaceYear )
66  {
67  if ( fmt.contains( 'M' ) )
68  {
69  // in case of also having 'M' we have a conflict about
70  // which year to show
71 
72  doReplaceYear = false;
73  }
74  else
75  {
76  // in case of also having 'd' or 'dd' we have a conflict about
77  // which year to show
78 
79  int numD = 0;
80 
81  for ( int i = 0; i < fmt.size(); i++ )
82  {
83  if ( fmt[i] == 'd' )
84  {
85  numD++;
86  }
87  else
88  {
89  if ( numD > 0 && numD <= 2 )
90  break;
91 
92  numD = 0;
93  }
94  }
95 
96  if ( numD > 0 && numD <= 2 )
97  doReplaceYear = false;
98  }
99  }
100 
101  if ( doReplaceYear )
102  {
103  const QDate dt( dateTime.date().year() + 1, 1, 1 );
104  const QString dtString = QLocale().toString( dt, s_yyyy );
105 
106  if ( fmt.contains( s_yyyy ) )
107  {
108  fmt.replace( s_yyyy, dtString );
109  }
110  else
111  {
112  fmt.replace( s_yy, dtString );
113  }
114  }
115  }
116 
117  return fmt;
118 }
119 
120 static inline Qt::DayOfWeek qwtFirstDayOfWeek()
121 {
122  return QLocale().firstDayOfWeek();
123 }
124 
125 static inline void qwtFloorTime(
126  QwtDate::IntervalType intervalType, QDateTime &dt )
127 {
128  // when dt is inside the special hour where DST is ending
129  // an hour is no unique. Therefore we have to
130  // use UTC time.
131 
132  const Qt::TimeSpec timeSpec = dt.timeSpec();
133 
134  if ( timeSpec == Qt::LocalTime )
135  dt = dt.toTimeSpec( Qt::UTC );
136 
137  const QTime t = dt.time();
138  switch( intervalType )
139  {
140  case QwtDate::Second:
141  {
142  dt.setTime( QTime( t.hour(), t.minute(), t.second() ) );
143  break;
144  }
145  case QwtDate::Minute:
146  {
147  dt.setTime( QTime( t.hour(), t.minute(), 0 ) );
148  break;
149  }
150  case QwtDate::Hour:
151  {
152  dt.setTime( QTime( t.hour(), 0, 0 ) );
153  break;
154  }
155  default:
156  break;
157  }
158 
159  if ( timeSpec == Qt::LocalTime )
160  dt = dt.toTimeSpec( Qt::LocalTime );
161 }
162 
163 static inline QDateTime qwtToTimeSpec(
164  const QDateTime &dt, Qt::TimeSpec spec )
165 {
166  if ( dt.timeSpec() == spec )
167  return dt;
168 
169  const qint64 jd = dt.date().toJulianDay();
170  if ( jd < 0 || jd >= std::numeric_limits<int>::max() )
171  {
172  // the conversion between local time and UTC
173  // is internally limited. To avoid
174  // overflows we simply ignore the difference
175  // for those dates
176 
177  QDateTime dt2 = dt;
178  dt2.setTimeSpec( spec );
179  return dt2;
180  }
181 
182  return dt.toTimeSpec( spec );
183 }
184 
185 #if 0
186 
187 static inline double qwtToJulianDay( int year, int month, int day )
188 {
189  // code from QDate but using doubles to avoid overflows
190  // for large values
191 
192  const int m1 = ( month - 14 ) / 12;
193  const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
194  const double y1 = std::floor( ( 4900.0 + year + m1 ) / 100 );
195 
196  return std::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
197  - std::floor( ( 3 * y1 ) / 4 ) + day - 32075;
198 }
199 
200 static inline qint64 qwtFloorDiv64( qint64 a, int b )
201 {
202  if ( a < 0 )
203  a -= b - 1;
204 
205  return a / b;
206 }
207 
208 static inline qint64 qwtFloorDiv( int a, int b )
209 {
210  if ( a < 0 )
211  a -= b - 1;
212 
213  return a / b;
214 }
215 
216 #endif
217 
218 static inline QDate qwtToDate( int year, int month = 1, int day = 1 )
219 {
220 #if QT_VERSION >= 0x050000
221  return QDate( year, month, day );
222 #else
223  if ( year > 100000 )
224  {
225  // code from QDate but using doubles to avoid overflows
226  // for large values
227 
228  const int m1 = ( month - 14 ) / 12;
229  const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
230  const double y1 = std::floor( ( 4900.0 + year + m1 ) / 100 );
231 
232  const double jd = std::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
233  - std::floor( ( 3 * y1 ) / 4 ) + day - 32075;
234 
235  if ( jd > maxJulianDayD )
236  {
237  qWarning() << "qwtToDate: overflow";
238  return QDate();
239  }
240 
241  return QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
242  }
243  else
244  {
245  return QDate( year, month, day );
246  }
247 #endif
248 }
249 
261 QDateTime QwtDate::toDateTime( double value, Qt::TimeSpec timeSpec )
262 {
263  const int msecsPerDay = 86400000;
264 
265  const double days = static_cast<qint64>( std::floor( value / msecsPerDay ) );
266 
267  const double jd = QwtDate::JulianDayForEpoch + days;
268  if ( ( jd > maxJulianDayD ) || ( jd < minJulianDayD ) )
269  {
270  qWarning() << "QwtDate::toDateTime: overflow";
271  return QDateTime();
272  }
273 
274  const QDate d = QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
275 
276  const int msecs = static_cast<int>( value - days * msecsPerDay );
277 
278  static const QTime timeNull( 0, 0, 0, 0 );
279 
280  QDateTime dt( d, timeNull.addMSecs( msecs ), Qt::UTC );
281 
282  if ( timeSpec == Qt::LocalTime )
283  dt = qwtToTimeSpec( dt, timeSpec );
284 
285  return dt;
286 }
287 
298 double QwtDate::toDouble( const QDateTime &dateTime )
299 {
300  const int msecsPerDay = 86400000;
301 
302  const QDateTime dt = qwtToTimeSpec( dateTime, Qt::UTC );
303 
304  const double days = dt.date().toJulianDay() - QwtDate::JulianDayForEpoch;
305 
306  const QTime time = dt.time();
307  const double secs = 3600.0 * time.hour() +
308  60.0 * time.minute() + time.second();
309 
310  return days * msecsPerDay + time.msec() + 1000.0 * secs;
311 }
312 
323 QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType )
324 {
325  if ( dateTime.date() >= QwtDate::maxDate() )
326  return dateTime;
327 
328  QDateTime dt = dateTime;
329 
330  switch ( intervalType )
331  {
333  {
334  break;
335  }
336  case QwtDate::Second:
337  {
339  if ( dt < dateTime )
340  dt = dt.addSecs( 1 );
341 
342  break;
343  }
344  case QwtDate::Minute:
345  {
347  if ( dt < dateTime )
348  dt = dt.addSecs( 60 );
349 
350  break;
351  }
352  case QwtDate::Hour:
353  {
355  if ( dt < dateTime )
356  dt = dt.addSecs( 3600 );
357 
358  break;
359  }
360  case QwtDate::Day:
361  {
362  dt.setTime( QTime( 0, 0 ) );
363  if ( dt < dateTime )
364  dt = dt.addDays( 1 );
365 
366  break;
367  }
368  case QwtDate::Week:
369  {
370  dt.setTime( QTime( 0, 0 ) );
371  if ( dt < dateTime )
372  dt = dt.addDays( 1 );
373 
374  int days = qwtFirstDayOfWeek() - dt.date().dayOfWeek();
375  if ( days < 0 )
376  days += 7;
377 
378  dt = dt.addDays( days );
379 
380  break;
381  }
382  case QwtDate::Month:
383  {
384  dt.setTime( QTime( 0, 0 ) );
385  dt.setDate( qwtToDate( dateTime.date().year(),
386  dateTime.date().month() ) );
387 
388  if ( dt < dateTime )
389  dt = dt.addMonths( 1 );
390 
391  break;
392  }
393  case QwtDate::Year:
394  {
395  dt.setTime( QTime( 0, 0 ) );
396 
397  const QDate d = dateTime.date();
398 
399  int year = d.year();
400  if ( d.month() > 1 || d.day() > 1 || !dateTime.time().isNull() )
401  year++;
402 
403  if ( year == 0 )
404  year++; // there is no year 0
405 
406  dt.setDate( qwtToDate( year ) );
407  break;
408  }
409  }
410 
411  return dt;
412 }
413 
425 QDateTime QwtDate::floor( const QDateTime &dateTime,
426  IntervalType intervalType )
427 {
428  if ( dateTime.date() <= QwtDate::minDate() )
429  return dateTime;
430 
431  QDateTime dt = dateTime;
432 
433  switch ( intervalType )
434  {
436  {
437  break;
438  }
439  case QwtDate::Second:
440  case QwtDate::Minute:
441  case QwtDate::Hour:
442  {
443  qwtFloorTime( intervalType, dt );
444  break;
445  }
446  case QwtDate::Day:
447  {
448  dt.setTime( QTime( 0, 0 ) );
449  break;
450  }
451  case QwtDate::Week:
452  {
453  dt.setTime( QTime( 0, 0 ) );
454 
455  int days = dt.date().dayOfWeek() - qwtFirstDayOfWeek();
456  if ( days < 0 )
457  days += 7;
458 
459  dt = dt.addDays( -days );
460 
461  break;
462  }
463  case QwtDate::Month:
464  {
465  dt.setTime( QTime( 0, 0 ) );
466 
467  const QDate date = qwtToDate( dt.date().year(),
468  dt.date().month() );
469  dt.setDate( date );
470 
471  break;
472  }
473  case QwtDate::Year:
474  {
475  dt.setTime( QTime( 0, 0 ) );
476 
477  const QDate date = qwtToDate( dt.date().year() );
478  dt.setDate( date );
479 
480  break;
481  }
482  }
483 
484  return dt;
485 }
486 
500 {
501  static QDate date;
502  if ( !date.isValid() )
503  date = QDate::fromJulianDay( minJulianDayD );
504 
505  return date;
506 }
507 
522 {
523  static QDate date;
524  if ( !date.isValid() )
525  date = QDate::fromJulianDay( maxJulianDayD );
526 
527  return date;
528 }
529 
543 {
544  const Qt::DayOfWeek firstDayOfWeek = qwtFirstDayOfWeek();
545 
546  QDate dt0( year, 1, 1 );
547 
548  // floor to the first day of the week
549  int days = dt0.dayOfWeek() - firstDayOfWeek;
550  if ( days < 0 )
551  days += 7;
552 
553  dt0 = dt0.addDays( -days );
554 
555  if ( type == QwtDate::FirstThursday )
556  {
557  // according to ISO 8601 the first week is defined
558  // by the first thursday.
559 
560  int d = Qt::Thursday - firstDayOfWeek;
561  if ( d < 0 )
562  d += 7;
563 
564  if ( dt0.addDays( d ).year() < year )
565  dt0 = dt0.addDays( 7 );
566  }
567 
568  return dt0;
569 }
570 
585 int QwtDate::weekNumber( const QDate &date, Week0Type type )
586 {
587  int weekNo;
588 
589  if ( type == QwtDate::FirstDay )
590  {
591  QDate day0;
592 
593  if ( date.month() == 12 && date.day() >= 24 )
594  {
595  // week 1 usually starts in the previous years.
596  // and we have to check if we are already there
597 
598  day0 = dateOfWeek0( date.year() + 1, type );
599  if ( day0.daysTo( date ) < 0 )
600  day0 = dateOfWeek0( date.year(), type );
601  }
602  else
603  {
604  day0 = dateOfWeek0( date.year(), type );
605  }
606 
607  weekNo = day0.daysTo( date ) / 7 + 1;
608  }
609  else
610  {
611  weekNo = date.weekNumber();
612  }
613 
614  return weekNo;
615 }
616 
635 int QwtDate::utcOffset( const QDateTime &dateTime )
636 {
637  int seconds = 0;
638 
639  switch( dateTime.timeSpec() )
640  {
641  case Qt::UTC:
642  {
643  break;
644  }
645  case Qt::OffsetFromUTC:
646  {
647 #if QT_VERSION >= 0x050200
648  seconds = dateTime.offsetFromUtc();
649 #else
650  seconds = dateTime.utcOffset();
651 #endif
652  break;
653  }
654  default:
655  {
656  const QDateTime dt1( dateTime.date(), dateTime.time(), Qt::UTC );
657  seconds = dateTime.secsTo( dt1 );
658  }
659  }
660 
661  return seconds;
662 }
663 
686 QString QwtDate::toString( const QDateTime &dateTime,
687  const QString & format, Week0Type week0Type )
688 {
689  QString fmt = format;
690  if ( fmt.contains( 'w' ) )
691  {
692  fmt = qwtExpandedFormat( fmt, dateTime, week0Type );
693  }
694 
695  return QLocale().toString( dateTime, fmt );
696 }
static Qt::DayOfWeek qwtFirstDayOfWeek()
Definition: qwt_date.cpp:120
The interval is related to weeks.
Definition: qwt_date.h:93
enum MQTTPropertyCodes value
The interval is related to years.
Definition: qwt_date.h:99
The interval is related to months.
Definition: qwt_date.h:96
FMT_INLINE std::basic_string< Char > format(const S &format_str, Args &&...args)
Definition: core.h:2081
static QDateTime qwtToTimeSpec(const QDateTime &dt, Qt::TimeSpec spec)
Definition: qwt_date.cpp:163
MQTTClient d
Definition: test10.c:1656
static QDate maxDate()
Definition: qwt_date.cpp:521
static QDateTime floor(const QDateTime &, IntervalType)
Definition: qwt_date.cpp:425
static double toDouble(const QDateTime &)
Definition: qwt_date.cpp:298
static const QwtJulianDay maxJulianDayD
Definition: qwt_date.cpp:32
int QwtJulianDay
Definition: qwt_date.cpp:30
IntervalType
Definition: qwt_date.h:75
The interval is related to minutes.
Definition: qwt_date.h:84
#define max(A, B)
Definition: Socket.h:88
static const QwtJulianDay minJulianDayD
Definition: qwt_date.cpp:31
The interval is related to hours.
Definition: qwt_date.h:87
static int utcOffset(const QDateTime &)
Definition: qwt_date.cpp:635
The Julian day of "The Epoch".
Definition: qwt_date.h:105
The interval is related to milliseconds.
Definition: qwt_date.h:78
Week0Type
Definition: qwt_date.h:49
static QDateTime ceil(const QDateTime &, IntervalType)
Definition: qwt_date.cpp:323
static QString qwtExpandedFormat(const QString &format, const QDateTime &dateTime, QwtDate::Week0Type week0Type)
Definition: qwt_date.cpp:36
float time
Definition: mqtt_test.py:17
static int weekNumber(const QDate &, Week0Type)
Definition: qwt_date.cpp:585
static QDate dateOfWeek0(int year, Week0Type)
Date of the first day of the first week for a year.
Definition: qwt_date.cpp:542
static QDateTime toDateTime(double value, Qt::TimeSpec=Qt::UTC)
Definition: qwt_date.cpp:261
static QDate minDate()
Definition: qwt_date.cpp:499
static QString toString(const QDateTime &, const QString &format, Week0Type)
Definition: qwt_date.cpp:686
The interval is related to seconds.
Definition: qwt_date.h:81
static void qwtFloorTime(QwtDate::IntervalType intervalType, QDateTime &dt)
Definition: qwt_date.cpp:125
static QDate qwtToDate(int year, int month=1, int day=1)
Definition: qwt_date.cpp:218
The interval is related to days.
Definition: qwt_date.h:90


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:48:10