1 #include <google/protobuf/stubs/time.h>
5 #include <google/protobuf/stubs/stringprintf.h>
6 #include <google/protobuf/stubs/strutil.h>
13 static const int64 kSecondsPerMinute = 60;
14 static const int64 kSecondsPerHour = 3600;
15 static const int64 kSecondsPerDay = kSecondsPerHour * 24;
16 static const int64 kSecondsPer400Years =
17 kSecondsPerDay * (400 * 365 + 400 / 4 - 3);
19 static const int64 kSecondsFromEraToEpoch = 62135596800
LL;
21 static const int64 kMinTime = -62135596800
LL;
22 static const int64 kMaxTime = 253402300799
LL;
24 static const int kNanosPerMillisecond = 1000000;
25 static const int kNanosPerMicrosecond = 1000;
29 int64 SecondsPer100Years(
int year) {
30 if (year % 400 == 0 || year % 400 > 300) {
31 return kSecondsPerDay * (100 * 365 + 100 / 4);
33 return kSecondsPerDay * (100 * 365 + 100 / 4 - 1);
39 int64 SecondsPer4Years(
int year) {
40 if ((year % 100 == 0 || year % 100 > 96) &&
41 !(year % 400 == 0 || year % 400 > 396)) {
43 return kSecondsPerDay * (4 * 365);
46 return kSecondsPerDay * (4 * 365 + 1);
50 bool IsLeapYear(
int year) {
51 return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
54 int64 SecondsPerYear(
int year) {
55 return kSecondsPerDay * (IsLeapYear(year) ? 366 : 365);
58 static const int kDaysInMonth[13] = {
59 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
62 int64 SecondsPerMonth(
int month,
bool leap) {
63 if (month == 2 && leap) {
64 return kSecondsPerDay * (kDaysInMonth[month] + 1);
66 return kSecondsPerDay * kDaysInMonth[month];
69 static const int kDaysSinceJan[13] = {
70 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
73 bool ValidateDateTime(
const DateTime& time) {
74 if (time.year < 1 || time.year > 9999 ||
75 time.month < 1 || time.month > 12 ||
76 time.day < 1 || time.day > 31 ||
77 time.hour < 0 || time.hour > 23 ||
78 time.minute < 0 || time.minute > 59 ||
79 time.second < 0 || time.second > 59) {
82 if (time.month == 2 && IsLeapYear(time.year)) {
83 return time.day <= kDaysInMonth[time.month] + 1;
85 return time.day <= kDaysInMonth[time.month];
91 int64 SecondsSinceCommonEra(
const DateTime& time) {
94 assert(time.year >= 1 && time.year <= 9999);
96 if ((time.year - year) >= 400) {
97 int count_400years = (time.year - year) / 400;
98 result += kSecondsPer400Years * count_400years;
99 year += count_400years * 400;
101 while ((time.year - year) >= 100) {
102 result += SecondsPer100Years(year);
105 while ((time.year - year) >= 4) {
106 result += SecondsPer4Years(year);
109 while (time.year > year) {
110 result += SecondsPerYear(year);
114 assert(time.month >= 1 && time.month <= 12);
115 int month = time.month;
116 result += kSecondsPerDay * kDaysSinceJan[month];
117 if (month > 2 && IsLeapYear(year)) {
120 assert(time.day >= 1 &&
121 time.day <= (month == 2 && IsLeapYear(year)
122 ? kDaysInMonth[month] + 1
123 : kDaysInMonth[month]));
124 result += kSecondsPerDay * (time.day - 1);
125 result += kSecondsPerHour * time.hour +
126 kSecondsPerMinute * time.minute +
134 if (nanos % kNanosPerMillisecond == 0) {
135 return StringPrintf(
"%03d", nanos / kNanosPerMillisecond);
136 }
else if (nanos % kNanosPerMicrosecond == 0) {
137 return StringPrintf(
"%06d", nanos / kNanosPerMicrosecond);
147 const char* ParseInt(
const char*
data,
int width,
int min_value,
148 int max_value,
int*
result) {
160 if (
value >= min_value &&
value <= max_value) {
170 const char* ParseNanos(
const char*
data,
int32* nanos) {
196 if ((
data = ParseInt(
data, 2, 0, 23, &hour)) ==
nullptr) {
199 if (*
data++ !=
':') {
203 if ((
data = ParseInt(
data, 2, 0, 59, &minute)) ==
nullptr) {
206 *
offset = (hour * 60 + minute) * 60;
212 if (seconds < kMinTime || seconds > kMaxTime) {
218 if (
seconds >= kSecondsPer400Years) {
219 int count_400years =
seconds / kSecondsPer400Years;
220 year += 400 * count_400years;
221 seconds %= kSecondsPer400Years;
223 while (
seconds >= SecondsPer100Years(year)) {
224 seconds -= SecondsPer100Years(year);
227 while (
seconds >= SecondsPer4Years(year)) {
228 seconds -= SecondsPer4Years(year);
231 while (
seconds >= SecondsPerYear(year)) {
232 seconds -= SecondsPerYear(year);
235 bool leap = IsLeapYear(year);
237 while (
seconds >= SecondsPerMonth(month, leap)) {
238 seconds -= SecondsPerMonth(month, leap);
241 int day = 1 +
seconds / kSecondsPerDay;
243 int hour =
seconds / kSecondsPerHour;
245 int minute =
seconds / kSecondsPerMinute;
251 time->minute = minute;
252 time->second =
static_cast<int>(
seconds);
257 if (!ValidateDateTime(time)) {
260 *
seconds = SecondsSinceCommonEra(time) - kSecondsFromEraToEpoch;
274 return "InvalidTime";
277 StringPrintf(
"%04d-%02d-%02dT%02d:%02d:%02d", time.year, time.month,
278 time.day, time.hour, time.minute, time.second);
280 result +=
"." + FormatNanos(nanos);
293 if ((
data = ParseInt(
data, 4, 1, 9999, &time.
year)) ==
nullptr) {
297 if (*
data++ !=
'-')
return false;
299 if ((
data = ParseInt(
data, 2, 1, 12, &time.
month)) ==
nullptr) {
303 if (*
data++ !=
'-')
return false;
305 if ((
data = ParseInt(
data, 2, 1, 31, &time.
day)) ==
nullptr) {
309 if (*
data++ !=
'T')
return false;
311 if ((
data = ParseInt(
data, 2, 0, 23, &time.
hour)) ==
nullptr) {
315 if (*
data++ !=
':')
return false;
321 if (*
data++ !=
':')
return false;
333 if ((
data = ParseNanos(
data, nanos)) ==
nullptr) {
342 }
else if (*
data ==
'+') {
349 }
else if (*
data ==
'-') {