codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / runtime / base / datetime.h
blob0889246415e7ed75458d26d6f68ed046348dc691
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_DATETIME_H_
18 #define incl_HPHP_DATETIME_H_
20 #include <memory>
22 #include "hphp/runtime/base/array-init.h"
23 #include "hphp/runtime/base/request-event-handler.h"
24 #include "hphp/runtime/base/req-ptr.h"
25 #include "hphp/runtime/base/timezone.h"
26 #include "hphp/runtime/base/dateinterval.h"
27 #include "hphp/runtime/base/request-local.h"
29 namespace HPHP {
30 ///////////////////////////////////////////////////////////////////////////////
32 /**
33 * Encapsulating all date/time manipulations, conversions, input and output
34 * into this one single class.
36 struct DateTime final : SweepableResourceData {
37 DECLARE_RESOURCE_ALLOCATION(DateTime);
39 /**
40 * Different RFC/ISO date/time formats for toString(DateFormat).
42 enum class DateFormat {
43 InvalidFormat,
45 /**
46 * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
47 * date-time = [ day "," ] date time ; dd mm yy hh:mm:ss zzz
48 * day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
49 * date = 1*2DIGIT month 2DIGIT ; day month year e.g. 20 Jun 82
50 * month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
51 * "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
52 * time = hour zone ; ANSI and Military
53 * hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
54 * zone = "UT" / "GMT" / "EST" / "EDT" / "CST" / "CDT" / "MST" /
55 * "MDT" / "PST" / "PDT" / 1ALPHA / (("+" / "-") 4DIGIT)
57 RFC822,
59 /**
60 * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
61 * Format must be acceptable both to the ARPANET and to the getdate
62 * routine. One format that is acceptable to both is Weekday,
63 * DD-Mon-YY HH:MM:SS TIMEZONE
64 * TIMEZONE can be any timezone name (3 or more letters)
66 RFC850,
68 /**
69 * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
70 * Its format must be acceptable both in RFC-822 and to the getdate(3)
71 * Wdy, DD Mon YY HH:MM:SS TIMEZONE
72 * There is no hope of having a complete list of timezones. Universal
73 * Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
74 * CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be
75 * supported.
77 RFC1036,
79 /**
80 * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
81 * RFC-822 Date and Time Specification: RFC-822 Section 5
82 * The syntax for the date is hereby changed to:
83 * date = 1*2DIGIT month 2*4DIGIT
85 RFC1123,
87 /**
88 * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
89 * FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
90 * CFWS = *([FWS] comment) (([FWS] comment) / FWS)
92 * date-time = [ day-of-week "," ] date FWS time [CFWS]
93 * day-of-week = ([FWS] day-name)
94 * day-name = "Mon"/"Tue"/"Wed"/"Thu"/"Fri"/"Sat"/"Sun"
95 * date = day month year
96 * year = 4*DIGIT
97 * month = (FWS month-name FWS)
98 * month-name = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
99 * "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
100 * day = ([FWS] 1*2DIGIT)
101 * time = time-of-day FWS zone
102 * time-of-day = hour ":" minute [ ":" second ]
103 * hour = 2DIGIT
104 * minute = 2DIGIT
105 * second = 2DIGIT
106 * zone = (( "+" / "-" ) 4DIGIT)
108 RFC2822,
111 * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
112 * date-fullyear = 4DIGIT
113 * date-month = 2DIGIT ; 01-12
114 * date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
115 * ; month/year
117 * time-hour = 2DIGIT ; 00-23
118 * time-minute = 2DIGIT ; 00-59
119 * time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on
120 * ; leap second rules
122 * time-secfrac = "." 1*DIGIT
123 * time-numoffset = ("+" / "-") time-hour ":" time-minute
124 * time-offset = "Z" / time-numoffset
126 * partial-time = time-hour ":" time-minute ":" time-second
127 * [time-secfrac]
128 * full-date = date-fullyear "-" date-month "-" date-mday
129 * full-time = partial-time time-offset
131 * date-time = full-date "T" full-time
133 RFC3339,
135 ISO8601,
138 * Preliminary specification:
139 * http://wp.netscape.com/newsref/std/cookie_spec.html
140 * "This is based on RFC 822, RFC 850, RFC 1036, and RFC 1123,
141 * with the variations that the only legal time zone is GMT
142 * and the separators between the elements of the date must be dashes."
144 Cookie,
147 * Similar to Cookie without dashes.
149 HttpHeader,
152 * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
153 * A Date construct is an element whose content MUST conform to the
154 * "date-time" production in [RFC3339]. In addition, an uppercase "T"
155 * character MUST be used to separate date and time, and an uppercase
156 * "Z" character MUST be present in the absence of a numeric time zone
157 * offset.
159 Atom = RFC3339,
162 * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
163 * "All date-times in RSS conform to the Date and Time Specification of
164 * RFC 822, with the exception that the year may be expressed with two
165 * characters or four characters (four preferred)"
167 RSS = RFC1123,
169 W3C = RFC3339,
173 * Different array formats for toArray().
175 enum class ArrayFormat {
176 TimeMap,
177 TmMap,
178 TmVector
182 * Different formats for getSunInfo().
184 enum class SunInfoFormat {
185 ReturnTimeStamp,
186 ReturnString,
187 ReturnDouble
190 public:
191 static const char *DateFormatRFC822;
192 static const char *DateFormatRFC850;
193 static const char *DateFormatRFC1036;
194 static const char *DateFormatRFC1123;
195 static const char *DateFormatRFC2822;
196 static const char *DateFormatRFC3339;
197 static const char *DateFormatISO8601;
198 static const char *DateFormatCookie;
199 static const char *DateFormatHttpHeader;
201 static const char *MonthNames[];
202 static const char *ShortMonthNames[];
203 static const char *WeekdayNames[];
204 static const char *ShortWeekdayNames[];
206 static const char *GetWeekdayName(int y, int m, int d);
207 static const char *GetShortWeekdayName(int y, int m, int d);
208 static const char *OrdinalSuffix(int number);
210 static bool IsLeap(int year);
211 static int DaysInMonth(int y, int m);
212 static bool IsValid(int y, int m, int d);
215 * What time is it?
217 static req::ptr<DateTime> Current(bool utc = false);
220 * Returns are really in special PHP formats, and please read datetime.cpp
221 * for details.
223 static Array Parse(const String& datetime);
224 static Array Parse(const String& format, const String& date);
225 static Array ParseAsStrptime(const String& format, const String& date);
227 public:
228 // constructor
229 DateTime();
230 DateTime(const DateTime&);
231 explicit DateTime(int64_t timestamp, bool utc = false); // from a timestamp
232 explicit DateTime(int64_t timestamp, req::ptr<TimeZone> tz);
234 CLASSNAME_IS("DateTime");
235 // overriding ResourceData
236 const String& o_getClassNameHook() const override { return classnameof(); }
238 // informational
239 bool local() const { return m_time->is_localtime;}
240 bool utc() const { return !m_time->is_localtime;}
241 int year() const { return m_time->y;}
242 int month() const { return m_time->m;}
243 int day() const { return m_time->d;}
244 int hour() const { return m_time->h;}
245 int hour12() const { return (m_time->h % 12) ? (int) m_time->h % 12 : 12;}
246 int minute() const { return m_time->i;}
247 int second() const { return m_time->s;}
248 double fraction() const { return m_time->f;}
249 int zoneType() const { return m_time->zone_type;}
250 int beat() const; // Swatch Beat a.k.a. Internet Time
251 int dow() const; // day of week
252 int doy() const; // day of year
253 int isoWeek() const;
254 int isoYear() const;
255 int isoDow() const;
256 int offset() const; // timezone offset from UTC
257 req::ptr<TimeZone> timezone() const { return m_tz->cloneTimeZone();}
259 const char *weekdayName() const;
260 const char *shortWeekdayName() const;
261 const char *monthName() const;
262 const char *shortMonthName() const;
264 // modifications
265 void set(int hour, int minute, int second, int month, int day, int year);
266 void setDate(int year, int month, int day);
267 void setISODate(int year, int week, int day = 1);
268 void setTime(int hour, int minute, int second = 0);
269 void setTimezone(req::ptr<TimeZone> tz);
270 bool modify(const String& diff); // PHP's date_modify() function, muy powerful
271 void add(const req::ptr<DateInterval>& interval);
272 void sub(const req::ptr<DateInterval>& interval);
274 // conversions
275 void toTm(struct tm &ta) const;
276 int64_t toTimeStamp(bool &err) const;
277 int64_t toInteger(char format) const;
278 String toString(const String& format, bool stdc = false) const;
279 String toString(DateFormat format) const;
280 Array toArray(ArrayFormat format) const;
281 void fromTimeStamp(int64_t timestamp, bool utc = false);
282 bool fromString(const String& input, req::ptr<TimeZone> tz,
283 const char* format=nullptr, bool throw_on_error = true);
285 // comparison
286 req::ptr<DateInterval> diff(req::ptr<DateTime> datetime2,
287 bool absolute = false);
288 int compare(req::ptr<DateTime> datetime2);
290 // cloning
291 req::ptr<DateTime> cloneDateTime() const;
293 // sun info
294 Array getSunInfo(double latitude, double longitude) const;
295 Variant getSunInfo(SunInfoFormat retformat,
296 double latitude, double longitude,
297 double zenith, double utc_offset, bool calc_sunset) const;
299 // Error access
300 private:
301 void internalModify(timelib_time *t);
302 void internalModifyRelative(timelib_rel_time *rel, bool have_relative,
303 int8_t bias);
304 struct LastErrors final : RequestEventHandler {
305 void requestInit() override {
306 m_errors = nullptr;
308 void requestShutdown() override {
309 if (m_errors) {
310 timelib_error_container_dtor(m_errors);
313 void set(timelib_error_container *ec) {
314 requestShutdown();
315 m_errors = ec;
317 Array getLastWarnings() const {
318 if (!m_errors) return empty_array();
319 ArrayInit ret(m_errors->warning_count, ArrayInit::Map{});
320 for(int i = 0; i < m_errors->warning_count; i++) {
321 timelib_error_message *em = m_errors->warning_messages + i;
322 ret.set(em->position, String(em->message, CopyString));
324 return ret.toArray();
326 Array getLastErrors() const {
327 if (!m_errors) return empty_array();
328 ArrayInit ret(m_errors->error_count, ArrayInit::Map{});
329 for(int i = 0; i < m_errors->error_count; i++) {
330 timelib_error_message *em = m_errors->error_messages + i;
331 ret.set(em->position, String(em->message, CopyString));
333 return ret.toArray();
336 private:
337 timelib_error_container *m_errors;
339 DECLARE_STATIC_REQUEST_LOCAL(LastErrors, s_lastErrors);
341 public:
342 static void setLastErrors(timelib_error_container *ec)
343 { s_lastErrors.get()->set(ec); }
344 static Array getLastWarnings()
345 { return s_lastErrors.get()->getLastWarnings(); }
346 static Array getLastErrors()
347 { return s_lastErrors.get()->getLastErrors(); }
349 private:
350 struct time_deleter {
351 void operator()(timelib_time *t) {
352 timelib_time_dtor(t);
355 typedef std::shared_ptr<timelib_time> TimePtr;
357 TimePtr m_time;
358 req::ptr<TimeZone> m_tz;
359 mutable int64_t m_timestamp;
360 mutable bool m_timestampSet;
362 // helpers
363 static Array ParseTime(timelib_time* time,
364 struct timelib_error_container* error);
365 void update();
366 String rfcFormat(const String& format) const;
367 String stdcFormat(const String& format) const;
370 ///////////////////////////////////////////////////////////////////////////////
373 #endif // incl_HPHP_DATETIME_H_