PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llcommon/lldate.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 338 lines | 237 code | 58 blank | 43 comment | 41 complexity | 5358c21cac189797b00a3c5e8cd71a18 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lldate.cpp
  3. * @author Phoenix
  4. * @date 2006-02-05
  5. * @brief Implementation of the date class
  6. *
  7. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #include "linden_common.h"
  29. #include "lldate.h"
  30. #include "apr_time.h"
  31. #include <time.h>
  32. #include <locale.h>
  33. #include <string>
  34. #include <iomanip>
  35. #include <sstream>
  36. #include "lltimer.h"
  37. #include "llstring.h"
  38. static const F64 DATE_EPOCH = 0.0;
  39. static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
  40. // should be APR_USEC_PER_SEC, but that relies on INT64_C which
  41. // isn't defined in glib under our build set up for some reason
  42. LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH)
  43. {
  44. }
  45. LLDate::LLDate(const LLDate& date) :
  46. mSecondsSinceEpoch(date.mSecondsSinceEpoch)
  47. {
  48. }
  49. LLDate::LLDate(F64 seconds_since_epoch) :
  50. mSecondsSinceEpoch(seconds_since_epoch)
  51. {
  52. }
  53. LLDate::LLDate(const std::string& iso8601_date)
  54. {
  55. if(!fromString(iso8601_date))
  56. {
  57. llwarns << "date " << iso8601_date << " failed to parse; "
  58. << "ZEROING IT OUT" << llendl;
  59. mSecondsSinceEpoch = DATE_EPOCH;
  60. }
  61. }
  62. std::string LLDate::asString() const
  63. {
  64. std::ostringstream stream;
  65. toStream(stream);
  66. return stream.str();
  67. }
  68. //@ brief Converts time in seconds since EPOCH
  69. // to RFC 1123 compliant date format
  70. // E.g. 1184797044.037586 == Wednesday, 18 Jul 2007 22:17:24 GMT
  71. // in RFC 1123. HTTP dates are always in GMT and RFC 1123
  72. // is one of the standards used and the prefered format
  73. std::string LLDate::asRFC1123() const
  74. {
  75. return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
  76. }
  77. LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format");
  78. std::string LLDate::toHTTPDateString (std::string fmt) const
  79. {
  80. LLFastTimer ft1(FT_DATE_FORMAT);
  81. time_t locSeconds = (time_t) mSecondsSinceEpoch;
  82. struct tm * gmt = gmtime (&locSeconds);
  83. return toHTTPDateString(gmt, fmt);
  84. }
  85. std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
  86. {
  87. LLFastTimer ft1(FT_DATE_FORMAT);
  88. // avoid calling setlocale() unnecessarily - it's expensive.
  89. static std::string prev_locale = "";
  90. std::string this_locale = LLStringUtil::getLocale();
  91. if (this_locale != prev_locale)
  92. {
  93. setlocale(LC_TIME, this_locale.c_str());
  94. prev_locale = this_locale;
  95. }
  96. // use strftime() as it appears to be faster than std::time_put
  97. char buffer[128];
  98. strftime(buffer, 128, fmt.c_str(), gmt);
  99. std::string res(buffer);
  100. #if LL_WINDOWS
  101. // Convert from locale-dependant charset to UTF-8 (EXT-8524).
  102. res = ll_convert_string_to_utf8_string(res);
  103. #endif
  104. return res;
  105. }
  106. void LLDate::toStream(std::ostream& s) const
  107. {
  108. apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
  109. apr_time_exp_t exp_time;
  110. if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
  111. {
  112. s << "1970-01-01T00:00:00Z";
  113. return;
  114. }
  115. s << std::dec << std::setfill('0');
  116. #if( LL_WINDOWS || __GNUC__ > 2)
  117. s << std::right;
  118. #else
  119. s.setf(ios::right);
  120. #endif
  121. s << std::setw(4) << (exp_time.tm_year + 1900)
  122. << '-' << std::setw(2) << (exp_time.tm_mon + 1)
  123. << '-' << std::setw(2) << (exp_time.tm_mday)
  124. << 'T' << std::setw(2) << (exp_time.tm_hour)
  125. << ':' << std::setw(2) << (exp_time.tm_min)
  126. << ':' << std::setw(2) << (exp_time.tm_sec);
  127. if (exp_time.tm_usec > 0)
  128. {
  129. s << '.' << std::setw(2)
  130. << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100));
  131. }
  132. s << 'Z'
  133. << std::setfill(' ');
  134. }
  135. bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const
  136. {
  137. apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC);
  138. apr_time_exp_t exp_time;
  139. if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS)
  140. {
  141. return false;
  142. }
  143. if (year)
  144. *year = exp_time.tm_year + 1900;
  145. if (month)
  146. *month = exp_time.tm_mon + 1;
  147. if (day)
  148. *day = exp_time.tm_mday;
  149. if (hour)
  150. *hour = exp_time.tm_hour;
  151. if (min)
  152. *min = exp_time.tm_min;
  153. if (sec)
  154. *sec = exp_time.tm_sec;
  155. return true;
  156. }
  157. bool LLDate::fromString(const std::string& iso8601_date)
  158. {
  159. std::istringstream stream(iso8601_date);
  160. return fromStream(stream);
  161. }
  162. bool LLDate::fromStream(std::istream& s)
  163. {
  164. struct apr_time_exp_t exp_time;
  165. apr_int32_t tm_part;
  166. int c;
  167. s >> tm_part;
  168. exp_time.tm_year = tm_part - 1900;
  169. c = s.get(); // skip the hypen
  170. if (c != '-') { return false; }
  171. s >> tm_part;
  172. exp_time.tm_mon = tm_part - 1;
  173. c = s.get(); // skip the hypen
  174. if (c != '-') { return false; }
  175. s >> tm_part;
  176. exp_time.tm_mday = tm_part;
  177. c = s.get(); // skip the T
  178. if (c != 'T') { return false; }
  179. s >> tm_part;
  180. exp_time.tm_hour = tm_part;
  181. c = s.get(); // skip the :
  182. if (c != ':') { return false; }
  183. s >> tm_part;
  184. exp_time.tm_min = tm_part;
  185. c = s.get(); // skip the :
  186. if (c != ':') { return false; }
  187. s >> tm_part;
  188. exp_time.tm_sec = tm_part;
  189. // zero out the unused fields
  190. exp_time.tm_usec = 0;
  191. exp_time.tm_wday = 0;
  192. exp_time.tm_yday = 0;
  193. exp_time.tm_isdst = 0;
  194. exp_time.tm_gmtoff = 0;
  195. // generate a time_t from that
  196. apr_time_t time;
  197. if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS)
  198. {
  199. return false;
  200. }
  201. F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC;
  202. // check for fractional
  203. c = s.peek();
  204. if(c == '.')
  205. {
  206. F64 fractional = 0.0;
  207. s >> fractional;
  208. seconds_since_epoch += fractional;
  209. }
  210. c = s.peek(); // check for offset
  211. if (c == '+' || c == '-')
  212. {
  213. S32 offset_sign = (c == '+') ? 1 : -1;
  214. S32 offset_hours = 0;
  215. S32 offset_minutes = 0;
  216. S32 offset_in_seconds = 0;
  217. s >> offset_hours;
  218. c = s.get(); // skip the colon a get the minutes if there are any
  219. if (c == ':')
  220. {
  221. s >> offset_minutes;
  222. }
  223. offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60;
  224. seconds_since_epoch -= offset_in_seconds;
  225. }
  226. else if (c != 'Z') { return false; } // skip the Z
  227. mSecondsSinceEpoch = seconds_since_epoch;
  228. return true;
  229. }
  230. bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec)
  231. {
  232. struct apr_time_exp_t exp_time;
  233. exp_time.tm_year = year - 1900;
  234. exp_time.tm_mon = month - 1;
  235. exp_time.tm_mday = day;
  236. exp_time.tm_hour = hour;
  237. exp_time.tm_min = min;
  238. exp_time.tm_sec = sec;
  239. // zero out the unused fields
  240. exp_time.tm_usec = 0;
  241. exp_time.tm_wday = 0;
  242. exp_time.tm_yday = 0;
  243. exp_time.tm_isdst = 0;
  244. exp_time.tm_gmtoff = 0;
  245. // generate a time_t from that
  246. apr_time_t time;
  247. if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS)
  248. {
  249. return false;
  250. }
  251. mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC;
  252. return true;
  253. }
  254. F64 LLDate::secondsSinceEpoch() const
  255. {
  256. return mSecondsSinceEpoch;
  257. }
  258. void LLDate::secondsSinceEpoch(F64 seconds)
  259. {
  260. mSecondsSinceEpoch = seconds;
  261. }
  262. /* static */ LLDate LLDate::now()
  263. {
  264. // time() returns seconds, we want fractions of a second, which LLTimer provides --RN
  265. return LLDate(LLTimer::getTotalSeconds());
  266. }
  267. bool LLDate::operator<(const LLDate& rhs) const
  268. {
  269. return mSecondsSinceEpoch < rhs.mSecondsSinceEpoch;
  270. }
  271. std::ostream& operator<<(std::ostream& s, const LLDate& date)
  272. {
  273. date.toStream(s);
  274. return s;
  275. }
  276. std::istream& operator>>(std::istream& s, LLDate& date)
  277. {
  278. date.fromStream(s);
  279. return s;
  280. }