Changeset 74148 in vbox for trunk/src/VBox/Runtime
- Timestamp:
- Sep 7, 2018 6:50:54 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/time/time.cpp
r74125 r74148 800 800 801 801 /** 802 * Converts a time spec to a ISO date string, extended version. 803 * 804 * @returns Output string length on success (positive), VERR_BUFFER_OVERFLOW 805 * (negative) or VERR_OUT_OF_RANGE (negative) on failure. 806 * @param pTime The time. Caller should've normalized this. 807 * @param psz Where to store the string. 808 * @param cb The size of the buffer. 809 * @param cFractionDigits Number of digits in the fraction. Max is 9. 810 */ 811 RTDECL(ssize_t) RTTimeToStringEx(PCRTTIME pTime, char *psz, size_t cb, unsigned cFractionDigits) 812 { 813 size_t cch; 814 815 /* Format the fraction. */ 816 char szFraction[16]; 817 if (!cFractionDigits) 818 szFraction[0] = '\0'; 819 else 820 { 821 AssertReturn(cFractionDigits <= 9, VERR_OUT_OF_RANGE); 822 Assert(pTime->u32Nanosecond <= 999999999); 823 RTStrPrintf(szFraction, sizeof(szFraction), ".%09RU32", pTime->u32Nanosecond); 824 szFraction[cFractionDigits + 1] = '\0'; 825 } 826 827 /* (Default to UTC if not specified) */ 828 if ( (pTime->fFlags & RTTIME_FLAGS_TYPE_MASK) == RTTIME_FLAGS_TYPE_LOCAL 829 && pTime->offUTC) 830 { 831 int32_t offUTC = pTime->offUTC; 832 Assert(offUTC <= 840 && offUTC >= -840); 833 char chSign; 834 if (offUTC >= 0) 835 chSign = '+'; 836 else 837 { 838 chSign = '-'; 839 offUTC = -offUTC; 840 } 841 uint32_t offUTCHour = (uint32_t)offUTC / 60; 842 uint32_t offUTCMinute = (uint32_t)offUTC % 60; 843 844 /* Examples: 2018-09-07T16:12:00+02:00 2018-09-07T16:12:00.123456789+02:00 */ 845 cch = RTStrPrintf(psz, cb, 846 "%04RI32-%02u-%02uT%02u:%02u:%02u%s%c%02d%:02d", 847 pTime->i32Year, pTime->u8Month, pTime->u8MonthDay, 848 pTime->u8Hour, pTime->u8Minute, pTime->u8Second, szFraction, 849 chSign, offUTCHour, offUTCMinute); 850 if ( cch >= 24 851 && psz[cch - 6] == chSign) 852 return cch; 853 } 854 else 855 { 856 /* Examples: 2018-09-07T16:12:00Z 2018-09-07T16:12:00.123456789Z */ 857 cch = RTStrPrintf(psz, cb, "%04RI32-%02u-%02uT%02u:%02u:%02u%sZ", 858 pTime->i32Year, pTime->u8Month, pTime->u8MonthDay, 859 pTime->u8Hour, pTime->u8Minute, pTime->u8Second, szFraction); 860 if ( cch >= 19 861 && psz[cch - 1] == 'Z') 862 return cch; 863 } 864 return VERR_BUFFER_OVERFLOW; 865 } 866 RT_EXPORT_SYMBOL(RTTimeToStringEx); 867 868 869 /** 802 870 * Converts a time spec to a ISO date string. 803 871 * … … 841 909 842 910 /* 843 * The da ypart.911 * The date part. 844 912 */ 845 913 … … 912 980 return NULL; 913 981 914 /* Nanoseconds is optional and probably non-standard. */982 /* Just in case there is a fraction of seconds (should be!). */ 915 983 if (*pszString == '.') 916 984 { 985 const char * const pszStart = pszString; 917 986 rc = RTStrToUInt32Ex(pszString + 1, (char **)&pszString, 10, &pTime->u32Nanosecond); 918 987 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES) 919 988 return NULL; 989 if (pTime->u32Nanosecond >= 1000000000) 990 return NULL; 991 switch (pszString - pszStart) 992 { 993 case 1: pTime->u32Nanosecond *= 100000000; break; 994 case 2: pTime->u32Nanosecond *= 10000000; break; 995 case 3: pTime->u32Nanosecond *= 1000000; break; 996 case 4: pTime->u32Nanosecond *= 100000; break; 997 case 5: pTime->u32Nanosecond *= 10000; break; 998 case 6: pTime->u32Nanosecond *= 1000; break; 999 case 7: pTime->u32Nanosecond *= 100; break; 1000 case 8: pTime->u32Nanosecond *= 10; break; 1001 case 9: break; 1002 default: 1003 return NULL; 1004 } 920 1005 if (pTime->u32Nanosecond >= 1000000000) 921 1006 return NULL; … … 1059 1144 } 1060 1145 RT_EXPORT_SYMBOL(RTTimeToRfc2822); 1146 1147 1148 /** 1149 * Attempts to convert an RFC-2822 date string to a time structure. 1150 * 1151 * We're a little forgiving with zero padding, unspecified parts, and leading 1152 * and trailing spaces. 1153 * 1154 * @retval pTime on success, 1155 * @retval NULL on failure. 1156 * @param pTime Where to store the time on success. 1157 * @param pszString The ISO date string to convert. 1158 */ 1159 RTDECL(PRTTIME) RTTimeFromRfc2822(PRTTIME pTime, const char *pszString) 1160 { 1161 /* 1162 * Fri, 31 Aug 2018 00:00:00 +0200 1163 * Mon, 3 Sep 2018 00:00:00 GMT 1164 * Mon, 3 Sep 2018 00:00:00 -0000 1165 * 3 Sep 2018 00:00:00 -0000 (?) 1166 * 3 Sep 2018 00:00:00 GMT (?) 1167 * 1168 */ 1169 1170 /* Ignore leading spaces. */ 1171 while (RT_C_IS_SPACE(*pszString)) 1172 pszString++; 1173 1174 /* 1175 * Init non date & time parts. 1176 */ 1177 pTime->fFlags = RTTIME_FLAGS_TYPE_LOCAL; 1178 pTime->offUTC = 0; 1179 1180 /* 1181 * The date part. 1182 */ 1183 1184 /* Optional day of week: */ 1185 if (RT_C_IS_ALPHA(pszString[0])) 1186 pTime->u8WeekDay = UINT8_MAX; 1187 else if (pszString[0] != '\0' && pszString[1] != '\0') 1188 { 1189 uint32_t uWeekDay = RT_MAKE_U32_FROM_U8(RT_C_TO_LOWER(pszString[0]), RT_C_TO_LOWER(pszString[0]), 1190 RT_C_TO_LOWER(pszString[1]), 0); 1191 if ( uWeekDay == RT_MAKE_U32_FROM_U8('m', 'o', 'n', 0)) pTime->u8WeekDay = 0; 1192 else if (uWeekDay == RT_MAKE_U32_FROM_U8('t', 'u', 'e', 0)) pTime->u8WeekDay = 1; 1193 else if (uWeekDay == RT_MAKE_U32_FROM_U8('w', 'e', 'd', 0)) pTime->u8WeekDay = 2; 1194 else if (uWeekDay == RT_MAKE_U32_FROM_U8('t', 'h', 'u', 0)) pTime->u8WeekDay = 3; 1195 else if (uWeekDay == RT_MAKE_U32_FROM_U8('f', 'r', 'i', 0)) pTime->u8WeekDay = 4; 1196 else if (uWeekDay == RT_MAKE_U32_FROM_U8('s', 'a', 't', 0)) pTime->u8WeekDay = 5; 1197 else if (uWeekDay == RT_MAKE_U32_FROM_U8('s', 'u', 'n', 0)) pTime->u8WeekDay = 6; 1198 else 1199 return NULL; 1200 pszString += 3; 1201 while (RT_C_IS_ALPHA(*pszString)) 1202 pszString++; 1203 if (*pszString == ',') 1204 pszString++; 1205 while (RT_C_IS_SPACE(*pszString)) 1206 pszString++; 1207 if (!RT_C_IS_DIGIT(pszString[0])) 1208 return NULL; 1209 } 1210 else 1211 return NULL; 1212 1213 /* Day of month.*/ 1214 int rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8MonthDay); 1215 if (rc != VWRN_TRAILING_CHARS && rc != VINF_SUCCESS) 1216 return NULL; 1217 while (RT_C_IS_SPACE(*pszString)) 1218 pszString++; 1219 1220 /* Month of the year. */ 1221 if (pszString[0] == '\0' || pszString[1] == '\0' || pszString[2] == '\0') 1222 return NULL; 1223 uint32_t uMonth = RT_MAKE_U32_FROM_U8(RT_C_TO_LOWER(pszString[0]), RT_C_TO_LOWER(pszString[0]), 1224 RT_C_TO_LOWER(pszString[1]), 0); 1225 if ( uMonth == RT_MAKE_U32_FROM_U8('j', 'a', 'n', 0)) pTime->u8Month = 1; 1226 else if (uMonth == RT_MAKE_U32_FROM_U8('f', 'e', 'b', 0)) pTime->u8Month = 2; 1227 else if (uMonth == RT_MAKE_U32_FROM_U8('m', 'a', 'r', 0)) pTime->u8Month = 3; 1228 else if (uMonth == RT_MAKE_U32_FROM_U8('a', 'p', 'r', 0)) pTime->u8Month = 4; 1229 else if (uMonth == RT_MAKE_U32_FROM_U8('m', 'a', 'y', 0)) pTime->u8Month = 5; 1230 else if (uMonth == RT_MAKE_U32_FROM_U8('j', 'u', 'n', 0)) pTime->u8Month = 6; 1231 else if (uMonth == RT_MAKE_U32_FROM_U8('j', 'u', 'l', 0)) pTime->u8Month = 7; 1232 else if (uMonth == RT_MAKE_U32_FROM_U8('a', 'u', 'g', 0)) pTime->u8Month = 8; 1233 else if (uMonth == RT_MAKE_U32_FROM_U8('s', 'e', 'p', 0)) pTime->u8Month = 9; 1234 else if (uMonth == RT_MAKE_U32_FROM_U8('o', 'c', 't', 0)) pTime->u8Month = 10; 1235 else if (uMonth == RT_MAKE_U32_FROM_U8('n', 'o', 'v', 0)) pTime->u8Month = 11; 1236 else if (uMonth == RT_MAKE_U32_FROM_U8('d', 'e', 'c', 0)) pTime->u8Month = 12; 1237 else 1238 return NULL; 1239 pszString += 3; 1240 while (RT_C_IS_ALPHA(*pszString)) 1241 pszString++; 1242 while (RT_C_IS_SPACE(*pszString)) 1243 pszString++; 1244 1245 /* Year */ 1246 rc = RTStrToInt32Ex(pszString, (char **)&pszString, 10, &pTime->i32Year); 1247 if (rc != VWRN_TRAILING_CHARS) 1248 return NULL; 1249 1250 bool const fLeapYear = rtTimeIsLeapYear(pTime->i32Year); 1251 if (fLeapYear) 1252 pTime->fFlags |= RTTIME_FLAGS_LEAP_YEAR; 1253 1254 while (RT_C_IS_SPACE(*pszString)) 1255 pszString++; 1256 1257 1258 /* Calculate year day. */ 1259 unsigned const cDaysInMonth = fLeapYear 1260 ? g_acDaysInMonthsLeap[pTime->u8Month - 1] 1261 : g_acDaysInMonths[pTime->u8Month - 1]; 1262 if (pTime->u8MonthDay == 0 || pTime->u8MonthDay > cDaysInMonth) 1263 return NULL; 1264 1265 pTime->u16YearDay = pTime->u8MonthDay - 1 1266 + (fLeapYear 1267 ? g_aiDayOfYearLeap[pTime->u8Month - 1] 1268 : g_aiDayOfYear[pTime->u8Month - 1]); 1269 1270 /* 1271 * The time part. 1272 */ 1273 /* Hour. */ 1274 rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Hour); 1275 if (rc != VWRN_TRAILING_CHARS) 1276 return NULL; 1277 if (pTime->u8Hour > 23) 1278 return NULL; 1279 if (*pszString++ != ':') 1280 return NULL; 1281 1282 /* Minute. */ 1283 rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Minute); 1284 if (rc != VWRN_TRAILING_CHARS) 1285 return NULL; 1286 if (pTime->u8Minute > 59) 1287 return NULL; 1288 if (*pszString++ != ':') 1289 return NULL; 1290 1291 /* Second. */ 1292 rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &pTime->u8Second); 1293 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES) 1294 return NULL; 1295 if (pTime->u8Second > 59) 1296 return NULL; 1297 1298 /* Nanoseconds and probably non-standard. */ 1299 if (*pszString == '.') 1300 { 1301 const char * const pszStart = pszString; 1302 rc = RTStrToUInt32Ex(pszString + 1, (char **)&pszString, 10, &pTime->u32Nanosecond); 1303 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS && rc != VWRN_TRAILING_SPACES) 1304 return NULL; 1305 if (pTime->u32Nanosecond >= 1000000000) 1306 return NULL; 1307 switch (pszString - pszStart) 1308 { 1309 case 1: pTime->u32Nanosecond *= 100000000; break; 1310 case 2: pTime->u32Nanosecond *= 10000000; break; 1311 case 3: pTime->u32Nanosecond *= 1000000; break; 1312 case 4: pTime->u32Nanosecond *= 100000; break; 1313 case 5: pTime->u32Nanosecond *= 10000; break; 1314 case 6: pTime->u32Nanosecond *= 1000; break; 1315 case 7: pTime->u32Nanosecond *= 100; break; 1316 case 8: pTime->u32Nanosecond *= 10; break; 1317 case 9: break; 1318 default: 1319 return NULL; 1320 } 1321 if (pTime->u32Nanosecond >= 1000000000) 1322 return NULL; 1323 } 1324 else 1325 pTime->u32Nanosecond = 0; 1326 1327 /* 1328 * Time zone. 1329 */ 1330 if ( (pszString[0] == 'G' || pszString[0] == 'g') 1331 && (pszString[1] == 'M' || pszString[1] == 'm') 1332 && (pszString[2] == 'T' || pszString[2] == 't') ) 1333 { 1334 pszString++; 1335 pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK; 1336 pTime->fFlags |= ~RTTIME_FLAGS_TYPE_UTC; 1337 pTime->offUTC = 0; 1338 } 1339 else if ( *pszString == '+' 1340 || *pszString == '-') 1341 { 1342 if ( !RT_C_IS_DIGIT(pszString[1]) 1343 || !RT_C_IS_DIGIT(pszString[2])) 1344 return NULL; 1345 int8_t cUtcHours = (pszString[1] - '0') * 10 + (pszString[2] - '0'); 1346 if (*pszString == '-') 1347 cUtcHours = -cUtcHours; 1348 pszString += 3; 1349 1350 uint8_t cUtcMin = 0; 1351 if (RT_C_IS_DIGIT(pszString[0])) 1352 { 1353 rc = RTStrToUInt8Ex(pszString, (char **)&pszString, 10, &cUtcMin); 1354 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) 1355 return NULL; 1356 } 1357 else if (*pszString && !RT_C_IS_BLANK(*pszString)) 1358 return NULL; 1359 if (cUtcHours >= 0) 1360 pTime->offUTC = cUtcHours * 60 + cUtcMin; 1361 else 1362 pTime->offUTC = cUtcHours * 60 - cUtcMin; 1363 if (RT_ABS(pTime->offUTC) > 840) 1364 return NULL; 1365 } 1366 /* else: No time zone given, local with offUTC = 0. */ 1367 1368 /* 1369 * The rest of the string should be blanks. 1370 */ 1371 char ch; 1372 while ((ch = *pszString++) != '\0') 1373 if (!RT_C_IS_BLANK(ch)) 1374 return NULL; 1375 1376 return pTime; 1377 } 1378 RT_EXPORT_SYMBOL(RTTimeFromRfc2822); 1061 1379 1062 1380
Note:
See TracChangeset
for help on using the changeset viewer.