/indra/newview/lldateutil.cpp
C++ | 215 lines | 125 code | 30 blank | 60 comment | 18 complexity | 8b05da765fcdf678946557b334315849 MD5 | raw file
Possible License(s): LGPL-2.1
1/**
2* @file lldateutil.cpp
3*
4* $LicenseInfo:firstyear=2009&license=viewerlgpl$
5* Second Life Viewer Source Code
6* Copyright (C) 2010, Linden Research, Inc.
7*
8* This library is free software; you can redistribute it and/or
9* modify it under the terms of the GNU Lesser General Public
10* License as published by the Free Software Foundation;
11* version 2.1 of the License only.
12*
13* This library is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16* Lesser General Public License for more details.
17*
18* You should have received a copy of the GNU Lesser General Public
19* License along with this library; if not, write to the Free Software
20* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21*
22* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
23* $/LicenseInfo$
24*/
25
26#include "llviewerprecompiledheaders.h"
27
28#include "lldateutil.h"
29
30#include <boost/date_time/gregorian/gregorian.hpp>
31#include <boost/date_time/posix_time/ptime.hpp>
32
33// Linden libraries
34#include "lltrans.h"
35#include "llui.h"
36
37using namespace boost::gregorian;
38using namespace boost::posix_time;
39
40static S32 DAYS_PER_MONTH_NOLEAP[] =
41 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
42static S32 DAYS_PER_MONTH_LEAP[] =
43 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
44
45static S32 days_from_month(S32 year, S32 month)
46{
47 llassert_always(1 <= month);
48 llassert_always(month <= 12);
49
50 if (year % 4 == 0
51 && year % 100 != 0)
52 {
53 // leap year
54 return DAYS_PER_MONTH_LEAP[month - 1];
55 }
56 else
57 {
58 return DAYS_PER_MONTH_NOLEAP[month - 1];
59 }
60}
61
62bool LLDateUtil::dateFromPDTString(LLDate& date, const std::string& str)
63{
64 S32 month, day, year;
65 S32 matched = sscanf(str.c_str(), "%d/%d/%d", &month, &day, &year);
66 if (matched != 3) return false;
67 date.fromYMDHMS(year, month, day);
68 F64 secs_since_epoch = date.secondsSinceEpoch();
69 // Correct for the fact that specified date is in Pacific time, == UTC - 8
70 secs_since_epoch += 8.0 * 60.0 * 60.0;
71 date.secondsSinceEpoch(secs_since_epoch);
72 return true;
73}
74
75std::string LLDateUtil::ageFromDate(const LLDate& born_date, const LLDate& now)
76{
77 S32 born_month, born_day, born_year;
78 // explode out to month/day/year again
79 born_date.split(&born_year, &born_month, &born_day);
80
81 S32 now_year, now_month, now_day;
82 now.split(&now_year, &now_month, &now_day);
83
84 // Do grade-school subtraction, from right-to-left, borrowing from the left
85 // when things go negative
86 S32 age_days = (now_day - born_day);
87 if (age_days < 0)
88 {
89 now_month -= 1;
90 if (now_month == 0)
91 {
92 now_year -= 1;
93 now_month = 12;
94 }
95 age_days += days_from_month(now_year, now_month);
96 }
97 S32 age_months = (now_month - born_month);
98 if (age_months < 0)
99 {
100 now_year -= 1;
101 age_months += 12;
102 }
103 S32 age_years = (now_year - born_year);
104
105 // Noun pluralization depends on language
106 std::string lang = LLUI::getLanguage();
107
108 // Try for age in round number of years
109 LLStringUtil::format_map_t args;
110
111 if (age_months > 0 || age_years > 0)
112 {
113 args["[AGEYEARS]"] =
114 LLTrans::getCountString(lang, "AgeYears", age_years);
115 args["[AGEMONTHS]"] =
116 LLTrans::getCountString(lang, "AgeMonths", age_months);
117
118 // We want to display times like:
119 // 2 year 2 months
120 // 2 years (implicitly 0 months)
121 // 11 months
122 if (age_years > 0)
123 {
124 if (age_months > 0)
125 {
126 return LLTrans::getString("YearsMonthsOld", args);
127 }
128 else
129 {
130 return LLTrans::getString("YearsOld", args);
131 }
132 }
133 else // age_years == 0
134 {
135 return LLTrans::getString("MonthsOld", args);
136 }
137 }
138 // you're 0 months old, display in weeks or days
139
140 // Now for age in weeks
141 S32 age_weeks = age_days / 7;
142 age_days = age_days % 7;
143 if (age_weeks > 0)
144 {
145 args["[AGEWEEKS]"] =
146 LLTrans::getCountString(lang, "AgeWeeks", age_weeks);
147 return LLTrans::getString("WeeksOld", args);
148 }
149
150 // Down to days now
151 if (age_days > 0)
152 {
153 args["[AGEDAYS]"] =
154 LLTrans::getCountString(lang, "AgeDays", age_days);
155 return LLTrans::getString("DaysOld", args);
156 }
157
158 return LLTrans::getString("TodayOld");
159}
160
161std::string LLDateUtil::ageFromDate(const std::string& date_string, const LLDate& now)
162{
163 LLDate born_date;
164
165 if (!dateFromPDTString(born_date, date_string))
166 return "???";
167
168 return ageFromDate(born_date, now);
169}
170
171std::string LLDateUtil::ageFromDate(const std::string& date_string)
172{
173 return ageFromDate(date_string, LLDate::now());
174}
175
176//std::string LLDateUtil::ageFromDateISO(const std::string& date_string,
177// const LLDate& now)
178//{
179// S32 born_month, born_day, born_year;
180// S32 matched = sscanf(date_string.c_str(), "%d-%d-%d",
181// &born_year, &born_month, &born_day);
182// if (matched != 3) return "???";
183// date.fromYMDHMS(year, month, day);
184// F64 secs_since_epoch = date.secondsSinceEpoch();
185// // Correct for the fact that specified date is in Pacific time, == UTC - 8
186// secs_since_epoch += 8.0 * 60.0 * 60.0;
187// date.secondsSinceEpoch(secs_since_epoch);
188// return ageFromDate(born_year, born_month, born_day, now);
189//}
190//
191//std::string LLDateUtil::ageFromDateISO(const std::string& date_string)
192//{
193// return ageFromDateISO(date_string, LLDate::now());
194//}
195
196S32 LLDateUtil::secondsSinceEpochFromString(const std::string& format, const std::string& str)
197{
198 date_input_facet *facet = new date_input_facet(format);
199
200 std::stringstream ss;
201 ss << str;
202 ss.imbue(std::locale(ss.getloc(), facet));
203
204 date d;
205 ss >> d;
206
207 ptime time_t_date(d);
208 ptime time_t_epoch(date(1970,1,1));
209
210 // We assume that the date defined by str is in UTC, so the difference
211 // is calculated with no time zone corrections.
212 time_duration diff = time_t_date - time_t_epoch;
213
214 return diff.total_seconds();
215}