Line | Count | Source |
1 | | // This may look like C code, but it's really -*- C++ -*- |
2 | | /* |
3 | | * Copyright (C) 2009 Emweb bv, Herent, Belgium. |
4 | | * |
5 | | * See the LICENSE file for terms of use. |
6 | | */ |
7 | | #ifndef WTIME_H_ |
8 | | #define WTIME_H_ |
9 | | |
10 | | #include <Wt/WDateTime.h> |
11 | | #include <Wt/WString.h> |
12 | | #include <Wt/WStringStream.h> |
13 | | #include <chrono> |
14 | | #include <exception> |
15 | | |
16 | | namespace Wt { |
17 | | |
18 | | /*! \class WTime Wt/WTime.h Wt/WTime.h |
19 | | * \brief A value class that defines a clock time. |
20 | | * |
21 | | * A clock time represents the time of day (usually 0 to 24 hour), up |
22 | | * to millisecond precision. |
23 | | * |
24 | | * As of version %3.3.1, the time class itself will no longer limit times |
25 | | * to the 24-hour range, but will allow any time (duration), including negative |
26 | | * values. |
27 | | * |
28 | | * \sa WDate, WDateTime |
29 | | */ |
30 | | class WT_API WTime |
31 | | { |
32 | | public: |
33 | | /*! \brief Construct a <i>Null</i> time. |
34 | | * |
35 | | * A time for which isNull() returns true. A <i>Null</i> time is also |
36 | | * invalid. |
37 | | * |
38 | | * \sa isValid(), isNull() |
39 | | */ |
40 | | WTime(); |
41 | | |
42 | | /*! \brief Construct a time given hour, minutes, seconds, and milliseconds. |
43 | | * |
44 | | * \p m and \p s have range 0-59, and \p ms has range 0-999. A duration can |
45 | | * be positive or negative depending on the sign of \p h. |
46 | | * |
47 | | * When the time is invalid, isValid() is set to \c false. |
48 | | */ |
49 | | WTime(int h, int m, int s = 0, int ms = 0); |
50 | | |
51 | | #ifdef WT_DATE_TZ_USE_STD |
52 | | /*! \brief Convert std::chrono::hh_mm_ss to a WTime. |
53 | | */ |
54 | | WTime(const std::chrono::hh_mm_ss<std::chrono::duration<int, std::milli>>& time); |
55 | | |
56 | | /*! \brief Convert to std::chrono::hh_mm_ss. |
57 | | */ |
58 | | operator std::chrono::hh_mm_ss<std::chrono::duration<int, std::milli>>() const { return std::chrono::hh_mm_ss<std::chrono::duration<int, std::milli>>(toTimeDuration()); } |
59 | | #endif |
60 | | |
61 | | /*! \brief Sets the time. |
62 | | * |
63 | | * \p m and \p s have range 0-59, and \p ms has range 0-999. |
64 | | * |
65 | | * When the time is invalid, isValid() is set to \c false. |
66 | | */ |
67 | | bool setHMS(int h, int m, int s, int ms = 0); |
68 | | |
69 | | /*! \brief Adds seconds. |
70 | | * |
71 | | * Returns a time that is \p s seconds later than this time. Negative |
72 | | * values for \p s will result in a time that is as many seconds |
73 | | * earlier. |
74 | | */ |
75 | | WTime addSecs(int s) const; |
76 | | |
77 | | /*! \brief Adds milliseconds. |
78 | | * |
79 | | * Returns a time that is \p ms milliseconds later than this |
80 | | * time. Negative values for \p ms will result in a time that |
81 | | * is as many milliseconds earlier. |
82 | | */ |
83 | | WTime addMSecs(int ms) const; |
84 | | |
85 | | /*! \brief Returns if this time is <i>Null</i>. |
86 | | * |
87 | | * A null time is also invalid. |
88 | | * |
89 | | * \sa isValid(), WTime() |
90 | | */ |
91 | 0 | bool isNull() const { return null_; } |
92 | | |
93 | | /*! \brief Returns if this time is valid. |
94 | | */ |
95 | 0 | bool isValid() const { return valid_; } |
96 | | |
97 | | /*! \brief Returns the hour. |
98 | | */ |
99 | | int hour() const; |
100 | | |
101 | | /*! \brief Returns the minutes (0-59). |
102 | | */ |
103 | | int minute() const; |
104 | | |
105 | | /*! \brief Returns the seconds (0-59). |
106 | | */ |
107 | | int second() const; |
108 | | |
109 | | /*! \brief Returns the milliseconds (0-999) |
110 | | */ |
111 | | int msec() const; |
112 | | |
113 | | /*! \brief Returns the difference between two time values (in seconds). |
114 | | * |
115 | | * The result is negative if t is earlier than this. |
116 | | */ |
117 | | long secsTo(const WTime& t) const; |
118 | | |
119 | | /*! \brief Returns the difference between two time values (in milliseconds). |
120 | | * |
121 | | * The result is negative if t is earlier than this. |
122 | | */ |
123 | | long msecsTo(const WTime& t) const; |
124 | | |
125 | | /*! \brief Compares two time values. |
126 | | */ |
127 | | bool operator< (const WTime& other) const; |
128 | | |
129 | | /*! \brief Compares two time values. |
130 | | */ |
131 | | bool operator<= (const WTime& other) const; |
132 | | |
133 | | /*! \brief Compares two time values. |
134 | | */ |
135 | | bool operator> (const WTime& other) const; |
136 | | |
137 | | /*! \brief Compares two time values. |
138 | | */ |
139 | | bool operator>= (const WTime& other) const; |
140 | | |
141 | | /*! \brief Compares two time values. |
142 | | */ |
143 | | bool operator== (const WTime& other) const; |
144 | | |
145 | | /*! \brief Compares two time values. |
146 | | */ |
147 | | bool operator!= (const WTime& other) const; |
148 | | |
149 | | static WT_USTRING defaultFormat(); |
150 | | |
151 | | /*! \brief Formats this time to a string using a default format. |
152 | | * |
153 | | * The default format is "hh:mm:ss". |
154 | | */ |
155 | | WT_USTRING toString() const; |
156 | | |
157 | | /*! \brief Formats this time to a string using a specified format. |
158 | | * |
159 | | * The \p format is a string in which the following contents has |
160 | | * a special meaning. |
161 | | * |
162 | | * <table> |
163 | | * <tr><td><b>Code</b></td><td><b>Meaning</b></td> |
164 | | * <td><b>Example (for 14:06:23.045)</b></td></tr> |
165 | | * <tr><td>h</td><td>The hour without leading zero (0-23 or 1-12 for AM/PM display)</td> |
166 | | <td>14 or 2</td></tr> |
167 | | * <tr><td>hh</td><td>The hour with leading zero (00-23 or 01-12 for AM/PM display)</td> |
168 | | <td>14 or 02</td></tr> |
169 | | * <tr><td>H</td><td>The hour without leading zero (0-23)</td> |
170 | | <td>14</td></tr> |
171 | | * <tr><td>HH</td><td>The hour with leading zero (00-23)</td> |
172 | | <td>14</td></tr> |
173 | | * <tr><td>+ followed by (h/hh/H/HH)</td><td>The sign of the hour (+/-)</td> |
174 | | <td>+</td></tr> |
175 | | * <tr><td>m</td><td>The minutes without leading zero (0-59)</td> |
176 | | <td>6</td></tr> |
177 | | * <tr><td>mm</td><td>The minutes with leading zero (00-59)</td> |
178 | | <td>06</td></tr> |
179 | | * <tr><td>s</td><td>The seconds without leading zero (0-59)</td> |
180 | | <td>23</td></tr> |
181 | | * <tr><td>ss</td><td>The seconds with leading zero (00-59)</td> |
182 | | <td>23</td></tr> |
183 | | * <tr><td>z</td><td>The milliseconds without leading zero (0-999)</td> |
184 | | <td>45</td></tr> |
185 | | * <tr><td>zzz</td><td>The millisecons with leading zero (000-999)</td> |
186 | | <td>045</td></tr> |
187 | | * <tr><td>AP or A</td><td>use AM/PM display: affects h or hh display and is replaced itself by AM/PM</td> |
188 | | <td>PM</td></tr> |
189 | | * <tr><td>ap or a</td><td>use am/pm display: affects h or hh display and is replaced itself by am/pm</td> |
190 | | <td>pm</td></tr> |
191 | | * <tr><td>Z</td><td>the timezone in RFC 822 format (e.g. -0800)</td> |
192 | | <td>+0000</td></tr> |
193 | | * </table> |
194 | | * |
195 | | * Any other text is kept literally. String content between single |
196 | | * quotes (') are not interpreted as special codes. LabelOption::Inside a string, a literal |
197 | | * quote may be specifed using a double quote (''). |
198 | | * |
199 | | * Examples of format and result: |
200 | | * <table> |
201 | | * <tr><td><b>Format</b></td><td><b>Result (for 22:53:13.078)</b></td></tr> |
202 | | * <tr><td>hh:mm:ss.zzz</td><td>22:53:13.078</td></tr> |
203 | | * <tr><td>hh:mm:ss AP</td><td>10:53:13 PM</td></tr> |
204 | | * </table> |
205 | | * |
206 | | * \sa fromString(const WString& value, const WString& format) |
207 | | */ |
208 | | WT_USTRING toString(const WT_USTRING& format) const; |
209 | | |
210 | | /*! \brief Parses a string to a time using a default format. |
211 | | * |
212 | | * The default format is "hh:mm:ss". |
213 | | * For example, a time specified as: |
214 | | * \code |
215 | | * "22:55:15" |
216 | | * \endcode |
217 | | * will be parsed as a time that equals a time constructed as: |
218 | | * \code |
219 | | * WTime d(22,55,15); |
220 | | * \endcode |
221 | | * |
222 | | * When the time could not be parsed or is not valid, an invalid |
223 | | * time is returned (for which isValid() returns false). |
224 | | * |
225 | | * \sa fromString(const WString& s, const WString& format), isValid() |
226 | | */ |
227 | | static WTime fromString(const WT_USTRING& s); |
228 | | |
229 | | /*! \brief Parses a string to a time using a specified format. |
230 | | * |
231 | | * The \p format follows the same syntax as used by |
232 | | * \link toString(const WString& format) const toString(const WString& format)\endlink. |
233 | | * |
234 | | * When the time could not be parsed or is not valid, an invalid |
235 | | * time is returned (for which isValid() returns false). |
236 | | * |
237 | | * \sa toString(const WString&) const |
238 | | */ |
239 | | static WTime fromString(const WT_USTRING& s, const WT_USTRING& format); |
240 | | |
241 | | /*! \brief Reports the current client date. |
242 | | * |
243 | | * This method uses browser information to retrieve the time that is |
244 | | * configured in the client. |
245 | | * |
246 | | * \sa WLocalDateTime::currentDate() |
247 | | */ |
248 | | static WTime currentTime(); |
249 | | |
250 | | /*! \brief Reports the current server time. |
251 | | * |
252 | | * This method returns the local time on the server. |
253 | | * |
254 | | * \sa WDateTime::currentDateTime(), WLocalDateTime::currentServerDateTime() |
255 | | */ |
256 | | static WTime currentServerTime(); |
257 | | |
258 | | struct RegExpInfo { |
259 | | std::string regexp; |
260 | | std::string hourGetJS; |
261 | | std::string minuteGetJS; |
262 | | std::string secGetJS; |
263 | | std::string msecGetJS; |
264 | | }; |
265 | | |
266 | | static RegExpInfo formatToRegExp(const WT_USTRING& format); |
267 | | |
268 | | #ifndef WT_TARGET_JAVA |
269 | | std::chrono::duration<int, std::milli> toTimeDuration() const; |
270 | | static WTime fromTimeDuration(const std::chrono::duration<int, std::milli>& duration); |
271 | | #else |
272 | | std::chrono::milliseconds toTimeDuration() const; |
273 | | static WTime fromTimeDuration(const std::chrono::milliseconds& duration); |
274 | | #endif |
275 | | |
276 | | private: |
277 | | bool valid_, null_; |
278 | | long time_; |
279 | | |
280 | | WTime (long time); |
281 | | |
282 | | struct ParseState { |
283 | | int h, m, s, z, a; |
284 | | int hour, minute, sec, msec; |
285 | | bool pm, parseAMPM, haveAMPM; |
286 | | |
287 | | ParseState(); |
288 | | }; |
289 | | |
290 | | static bool parseLast(const std::string& v, unsigned& vi, |
291 | | ParseState& parse, const WString& format); |
292 | | |
293 | | static WDateTime::CharState handleSpecial(char c, const std::string& v, |
294 | | unsigned& vi, ParseState& parse, |
295 | | const WString& format); |
296 | | |
297 | | bool writeSpecial(const std::string& f, unsigned& i, WStringStream& result, |
298 | | bool useAMPM, int zoneOffset) const; |
299 | | |
300 | | int pmhour() const; |
301 | | |
302 | | static RegExpInfo formatHourToRegExp(RegExpInfo &result, const std::string& format, unsigned& i, int& currentGroup); |
303 | | static RegExpInfo formatMinuteToRegExp(RegExpInfo &result, const std::string& format, unsigned& i, int& currentGroup); |
304 | | static RegExpInfo formatSecondToRegExp(RegExpInfo &result, const std::string& format, unsigned& i, int& currentGroup); |
305 | | static RegExpInfo formatMSecondToRegExp(RegExpInfo &result, const std::string& format, unsigned& i, int& currentGroup); |
306 | | static RegExpInfo formatAPToRegExp(RegExpInfo &result, const std::string& format, unsigned& i); |
307 | | static RegExpInfo processChar(RegExpInfo &result, const std::string& format, unsigned& i); |
308 | | static bool usesAmPm(const WString& format); |
309 | | |
310 | | friend class WDateTime; |
311 | | friend class WTimePicker; |
312 | | }; |
313 | | |
314 | | } |
315 | | |
316 | | #endif // WTIME_H_ |