0001:
0002:
0003:
0004:
0005:
0006:
0007:
0008:
0009:
0010:
0011:
0012:
0013:
0014:
0015:
0016:
0017:
0018:
0019:
0020:
0021:
0022:
0023:
0024:
0025:
0026:
0027:
0028:
0029:
0030:
0031:
0032:
0033:
0034:
0035:
0036:
0037:
0038:
0039:
0040:
0041:
0042:
0043:
0044:
0045:
0046:
0047:
0048:
0049:
0050:
0051:
0052:
0053:
0054:
0055:
0056:
0057:
0058:
0059:
0060:
0061:
0062:
0063:
0064:
0065:
0066:
0067:
0068:
0069:
0070:
0071:
0072:
0073:
0074:
0075:
0076:
0077:
0078:
0079:
0080:
0081:
0082:
0083:
0084:
0085:
0086:
0087:
0088:
0089:
0090:
0091:
0092:
0093:
0094:
0095:
0096:
0097:
0098:
0099:
0100:
0101:
0102:
0103:
0104:
0105:
0106:
0107:
0108:
0109:
0110:
0111:
0112:
0113:
0114:
0115:
0116:
0117:
0118:
0119:
0120:
0121:
0122:
0123:
0124:
0125:
0126:
0127:
0128:
0129:
0130:
0131:
0132:
0133:
0134:
0135:
0136:
0137:
0138:
0139:
0140:
0141:
0142:
0143:
0144:
0145:
0146:
0147:
0148:
0149:
0150:
0151:
0152:
0153:
0154:
0155:
0156:
0157:
0158:
0159:
0160:
0161:
0162:
0163:
0164:
0165:
0166:
0167:
0168:
0169:
0170:
0171:
0172:
0173:
0174:
0175:
0176:
0177:
0178:
0179:
0180:
0181:
0182:
0183:
0184:
0185:
0186:
0187:
0188:
0189:
0190:
0191:
0192:
0193:
0194:
0195:
0196:
0197:
0198:
0199:
0200:
0201:
0202:
0203:
0204:
0205:
0206:
0207:
0208:
0209:
0210:
0211:
0212:
0213:
0214:
0215:
0216:
0217:
0218:
0219:
0220:
0221:
0222:
0223:
0224:
0225:
0226:
0227:
0228:
0229:
0230:
0231:
0232:
0233:
0234:
0235:
0236:
0237:
0238:
0239:
0240:
0241:
0242:
0243:
0244:
0245:
0246:
0247:
0248:
0249:
0250:
0251:
0252:
0253:
0254:
0255:
0256:
0257:
0258:
0259:
0260:
0261:
0262:
0263:
0264:
0265:
0266:
0267:
0268:
0269:
0270:
0271:
0272:
0273:
0274:
0275:
0276:
0277:
0278:
0279:
0280:
0281:
0282:
0283:
0284:
0285:
0286:
0287:
0288:
0289:
0290:
0291:
0292:
0293:
0294:
0295:
0296:
0297:
0298:
0299:
0300:
0301:
0302:
0303:
0304:
0305:
0306:
0307:
0308:
0309:
0310:
0311:
0312:
0313:
0314:
0315:
0316:
0317:
0318:
0319:
0320:
0321:
0322:
0323:
0324:
0325:
0326:
0327:
0328:
0329:
0330:
0331:
0332:
0333:
0334:
0335:
0336:
0337:
0338:
0339:
0340:
0341:
0342:
0343:
0344:
0345:
0346:
0347:
0348:
0349:
0350:
0351:
0352:
0353:
0354:
0355:
0356:
0357:
0358:
0359:
0360:
0361:
0362:
0363:
0364:
0365:
0366:
0367:
0368:
0369:
0370:
0371:
0372:
0373:
0374:
0375:
0376:
0377:
0378:
0379:
0380:
0381:
0382:
0383:
0384:
0385:
0386:
0387:
0388:
0389:
0390:
0391:
0392:
0393:
0394:
0395:
0396:
0397:
0398:
0399:
0400:
0401:
0402:
0403:
0404:
0405:
0406:
0407:
0408:
0409:
0410:
0411:
0412:
0413:
0414:
0415:
0416:
0417:
0418:
0419:
0420:
0421:
0422:
0423:
0424:
0425:
0426:
0427:
0428:
0429:
0430:
0431:
0432:
0433:
0434:
0435:
0436:
0437:
0438:
0439:
0440:
0441:
0442:
0443:
0444:
0445:
0446:
0447:
0448:
0449:
0450:
0451:
0452:
0453:
0454:
0455:
0456:
0457:
0458:
0459:
0460:
0461:
0462:
0463:
0464:
0465:
0466:
0467:
0468:
0469:
0470:
0471:
0472:
0473:
0474:
0475:
0476:
0477:
0478:
0479:
0480:
0481:
0482:
0483:
0484:
0485:
0486:
0487:
0488:
0489:
0490:
0491:
0492:
0493:
0494:
0495:
0496:
0497:
0498:
0499:
0500:
0501:
0502:
0503:
0504:
0505:
0506:
0507:
0508:
0509:
0510:
0511:
0512:
0513:
0514:
0515:
0516:
0517:
0518:
0519:
0520:
0521:
0522:
0523:
0524:
0525:
0526:
0527:
0528:
0529:
0530:
0531:
0532:
0533:
0534:
0535:
0536:
0537:
0538:
0539:
0540:
0541:
0542:
0543:
0544:
0545:
0546:
0547:
0548:
0549:
0550:
0551:
0552:
0553:
0554:
0555:
0556:
0557:
0558:
0559:
0560:
0561:
0562:
0563:
0564:
0565:
0566:
0567:
0568:
0569:
0570:
0571:
0572:
0573:
0574:
0575:
0576:
0577:
0578:
0579:
0580:
0581:
0582:
0583:
0584:
0585:
0586:
0587:
0588:
0589:
0590:
0591:
0592:
0593:
0594:
0595:
0596:
0597:
0598:
0599:
0600:
0601:
0602:
0603:
0604:
0605:
0606:
0607:
0608:
0609:
0610:
0611:
0612:
0613:
0614:
0615:
0616:
0617:
0618:
0619:
0620:
0621:
0622:
0623:
0624:
0625:
0626:
0627:
0628:
0629:
0630:
0631:
0632:
0633:
0634:
0635:
0636:
0637:
0638:
0639:
0640:
0641:
0642:
0643:
0644:
0645:
0646:
0647:
0648:
0649:
0650:
0651:
0652:
0653:
0654:
0655:
0656:
0657:
0658:
0659:
0660:
0661:
0662:
0663:
0664:
0665:
0666:
0667:
0668:
0669:
0670:
0671:
0672:
0673:
0674:
0675:
0676:
0677:
0678:
0679:
0680:
0681:
0682:
0683:
0684:
0685:
0686:
0687:
0688:
0689:
0690:
0691:
0692:
0693:
0694:
0695:
0696:
0697:
0698:
0699:
0700:
0701:
0702:
0703:
0704:
0705:
0706:
0707:
0708:
0709:
0710:
0711:
0712:
0713:
0714:
0715:
0716:
0717:
0718:
0719:
0720:
0721:
0722:
0723:
0724:
0725:
0726:
0727:
0728:
0729:
0730:
0731:
0732:
0733:
0734:
0735:
0736:
0737:
0738:
0739:
0740:
0741:
0742:
0743:
0744:
0745:
0746:
0747:
0748:
0749:
0750:
0751:
0752:
0753:
0754:
0755:
0756:
0757:
0758:
0759:
0760:
0761:
0762:
0763:
0764:
0765:
0766:
0767:
0768:
0769:
0770:
0771:
0772:
0773:
0774:
0775:
0776:
0777:
0778:
0779:
0780:
0781:
0782:
0783:
0784:
0785:
0786:
0787:
0788:
0789:
0790:
0791:
0792:
0793:
0794:
0795:
0796:
0797:
0798:
0799:
0800:
0801:
0802:
0803:
0804:
0805:
0806:
0807:
0808:
0809:
0810:
0811:
0812:
0813:
0814:
0815:
0816:
0817:
0818:
0819:
0820:
0821:
0822:
0823:
0824:
0825:
0826:
0827:
0828:
0829:
0830:
0831:
0832:
0833:
0834:
0835:
0836:
0837:
0838:
0839:
0840:
0841:
0842:
0843:
0844:
0845:
0846:
0847:
0848:
0849:
0850:
0851:
0852:
0853:
0854:
0855:
0856:
0857:
0858:
0859:
0860:
0861:
0862:
0863:
0864:
0865:
0866:
0867:
0868:
0869:
0870:
0871:
0872:
0873:
0874:
0875:
0876:
0877:
0878:
0879:
0880:
0881:
0882:
0883:
0884:
0885:
0886:
0887:
0888:
0889:
0890:
0891:
0892:
0893:
0894:
0895:
0896:
0897:
0898:
0899:
0900:
0901:
0902:
0903:
0904:
0905:
0906:
0907:
0908:
0909:
0910:
0911:
0912:
0913:
0914:
0915:
0916:
0917:
0918:
0919:
0920:
0921:
0922:
0923:
0924:
0925:
0926:
0927:
0928:
0929:
0930:
0931:
0932:
0933:
0934:
0935:
0936:
0937:
0938:
0939:
0940:
0941:
0942:
0943:
0944:
0945:
0946:
0947:
0948:
0949:
0950:
0951:
0952:
0953:
0954:
0955:
0956:
0957:
0958:
0959:
0960:
0961:
0962:
0963:
0964:
0965:
0966:
0967:
0968:
0969:
0970:
0971:
0972:
0973:
0974:
0975:
0976:
0977:
0978:
0979:
0980:
0981:
0982:
0983:
0984:
0985:
0986:
0987:
0988:
0989:
0990:
0991:
0992:
0993:
0994:
0995:
0996:
0997:
0998:
0999:
1000:
1001:
1002:
1003:
1004:
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
1064:
1065:
1066:
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075:
1076:
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089:
1090:
1091:
1092:
1093:
1094:
1095:
1096:
1097:
1098:
1099:
1100:
1101:
1102:
1103:
1104:
1105:
1106:
1107:
1108:
1109:
1110:
1111:
1112:
1113:
1114:
1115:
1116:
1117:
1118:
1119:
1120:
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129:
1130:
1131:
1132:
1133:
1134:
1135:
1136:
1137:
1138:
1139:
1140:
1141:
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153:
1154:
1155:
1156:
1157:
1158:
1159:
1160:
1161:
1162:
1163:
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181:
1182:
1183:
1184:
1185:
1186:
1187:
1188:
1189:
1190:
1191:
1192:
1193:
1194:
1195:
1196:
1197:
1198:
1199:
1200:
1201:
1202:
1203:
1204:
1205:
1206:
1207:
1208:
1209:
1210:
1211:
1212:
1213:
1214:
1215:
1216:
1217:
1218:
1219:
1220:
1221:
1222:
1223:
1224:
1225:
1226:
1227:
1228:
1229:
1230:
1231:
1232:
1233:
1234:
1235:
1236:
1237:
1238:
1239:
1240:
1241:
1242:
1243:
1244:
1245:
1246:
1247:
1248:
1249:
1250:
1251:
1252:
1253:
1254:
1255:
1256:
1257:
1258:
1259:
1260:
1261:
1262:
1263:
1264:
1265:
1266:
1267:
1268:
1269:
1270:
1271:
1272:
1273:
1274:
1275:
1276:
1277:
1278:
1279:
1280:
1281:
1282:
1283:
1284:
1285:
1286:
1287:
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
1296:
1297:
1298:
1299:
1300:
1301:
1302:
1303:
1304:
1305:
1306:
1307:
1308:
1309:
1310:
1311:
1312:
1313:
1314:
1315:
1316:
1317:
1318:
1319:
1320:
1321:
1322:
1323:
1324:
1325:
1326:
1327:
1328:
1329:
1330:
1331:
1332:
1333:
1334:
1335:
1336:
1337:
1338:
1339:
1340:
1341:
1342:
1343:
1344:
1345:
1346:
1347:
1348:
1349:
1350:
1351:
1352:
1353:
1354:
1355:
1356:
1357:
1358:
1359:
1360:
1361:
1362:
1363:
1364:
1365:
1366:
1367:
1368:
1369:
1370:
1371:
1372:
1373:
1374:
1375:
1376:
1377:
1378:
1379:
1380:
1381:
1382:
1383:
1384:
1385:
1386:
1387:
1388:
1389:
1390:
1391:
1392:
1393:
1394:
1395:
1396:
1397:
1398:
1399:
1400:
1401:
1402:
1403:
1404:
1405:
1406:
1407:
1408:
1409:
1410:
1411:
1412:
1413:
1414:
1415:
1416:
1417:
1418:
1419:
1420:
1421:
1422:
1423:
1424:
1425:
1426:
1427:
1428:
1429:
1430:
1431:
1432:
1433:
1434:
1435:
1436:
1437:
1438:
1439:
1440:
1441:
1442:
1443:
1444:
1445:
1446:
1447:
1448:
1449:
1450:
1451:
1452:
1453:
1454:
1455:
1456:
1457:
1458:
1459:
1460:
1461:
1462:
1463:
1464:
1465:
1466:
1467:
1468:
1469:
1470:
1471:
1472:
1473:
1474:
1475:
1476:
1477:
1478:
1479:
1480:
1481:
1482:
1483:
1484:
1485:
1486:
1487:
1488:
1489:
1490:
1491:
1492:
1493:
1494:
1495:
1496:
1497:
1498:
1499:
1500:
1501:
1502:
1503:
1504:
1505:
1506:
1507:
1508:
1509:
1510:
1511:
1512:
1513:
1514:
1515:
1516:
1517:
1518:
1519:
1520:
1521:
1522:
1523:
1524:
1525:
1526:
1527:
1528:
1529:
1530:
1531:
1532:
1533:
1534:
1535:
1536:
1537:
1538:
1539:
1540:
1541:
1542:
1543:
1544:
1545:
1546:
1547:
1548:
1549:
1550:
1551:
1552:
1553:
1554:
1555:
1556:
1557:
1558:
1559:
1560:
1561:
1562:
1563:
1564:
1565:
1566:
1567:
1568:
1569:
1570:
1571:
1572:
1573:
1574:
1575:
1576:
1577:
1578:
1579:
1580:
1581:
1582:
1583:
1584:
1585:
1586:
1587:
1588:
1589:
1590:
1591:
1592:
1593:
1594:
1595:
1596:
1597:
1598:
1599:
1600:
1601:
1602:
1603:
1604:
1605:
1606:
1607:
1608:
1609:
1610:
1611:
1612:
1613:
1614:
1615:
1616:
1617:
1618:
1619:
1620:
1621:
1622:
1623:
1624:
1625:
1626:
1627:
1628:
1629:
1630:
1631:
1632:
1633:
1634:
1635:
1636:
1637:
1638:
1639:
1640:
1641:
1642:
1643:
1644:
1645:
1646:
1647:
1648:
1649:
1650:
1651:
1652:
1653:
1654:
1655:
1656:
1657:
1658:
1659:
1660:
1661:
1662:
1663:
1664:
1665:
1666:
1667:
1668:
1669:
1670:
1671:
1672:
1673:
1674:
1675:
1676:
1677:
1678:
1679:
1680:
1681:
1682:
1683:
1684:
1685:
1686:
1687:
1688:
1689:
1690:
1691:
1692:
1693:
1694:
1695:
1696:
1697:
1698:
1699:
1700:
1701:
1702:
1703:
1704:
1705:
1706:
1707:
1708:
1709:
1710:
1711:
1712:
1713:
1714:
1715:
1716:
1717:
1718:
1719:
1720:
1721:
1722:
1723:
1724:
1725:
1726:
1727:
1728:
1729:
1730:
1731:
1732:
1733:
1734:
1735:
1736:
1737:
1738:
1739:
1740:
1741:
1742:
1743:
1744:
1745:
1746:
1747:
1748:
1749:
1750:
1751:
1752:
1753:
1754:
1755:
1756:
1757:
1758:
1759:
1760:
1761:
1762:
1763:
1764:
1765:
1766:
1767:
1768:
1769:
1770:
1771:
1772:
1773:
1774:
1775:
1776:
1777:
1778:
1779:
1780:
1781:
1782:
1783:
1784:
1785:
1786:
1787:
1788:
1789:
1790:
1791:
1792:
1793:
1794:
1795:
1796:
1797:
1798:
1799:
1800:
1801:
1802:
1803:
1804:
1805:
1806:
1807:
1808:
1809:
1810:
1811:
1812:
1813:
1814:
1815:
1816:
1817:
1818:
1819:
1820:
1821:
1822:
1823:
1824:
1825:
1826:
1827:
1828:
1829:
1830:
1831:
1832:
1833:
1834:
1835:
1836:
1837:
1838:
1839:
1840:
1841:
1842:
1843:
1844:
1845:
1846:
1847:
1848:
1849:
1850:
1851:
1852:
1853:
1854:
1855:
1856:
1857:
1858:
1859:
1860:
1861:
1862:
1863:
1864:
1865:
1866:
1867:
1868:
1869:
1870:
1871:
1872:
1873:
1874:
1875:
1876:
1877:
1878:
1879:
1880:
1881:
1882:
1883:
1884:
1885:
1886:
1887:
1888:
1889:
1890:
1891:
1892:
1893:
1894:
1895:
1896:
1897:
1898:
1899:
1900:
1901:
1902:
1903:
1904:
1905:
1906:
1907:
1908:
1909:
1910:
1911:
1912:
1913:
1914:
1915:
1916:
1917:
1918:
1919:
1920:
1921:
1922:
1923:
1924:
1925:
1926:
1927:
1928:
1929:
1930:
1931:
1932:
1933:
1934:
1935:
1936:
1937:
1938:
1939:
1940:
1941:
1942:
1943:
1944:
1945:
1946:
1947:
1948:
1949:
1950:
1951:
1952:
1953:
1954:
1955:
1956:
1957:
1958:
1959:
1960:
1961:
1962:
1963:
1964:
1965:
1966:
1967:
1968:
1969:
1970:
1971:
1972:
1973:
1974:
1975:
1976:
1977:
1978:
1979:
1980:
1981:
1982:
1983:
1984:
1985:
1986:
1987:
1988:
1989:
1990:
1991:
1992:
1993:
1994:
1995:
1996:
1997:
1998:
1999:
2000:
2001:
2002:
2003:
2004:
2005:
2006:
2007:
2008:
2009:
2010:
2011:
2012:
2013:
2014:
2015:
2016:
2017:
2018:
2019:
2020:
2021:
2022:
2023:
2024:
2025:
2026:
2027:
2028:
2029:
2030:
2031:
2032:
2033:
2034:
2035:
2036:
2037:
2038:
2039:
2040:
2041:
2042:
2043:
2044:
2045:
2046:
2047:
2048:
2049:
2050:
2051:
2052:
2053:
2054:
2055:
2056:
2057:
2058:
2059:
2060:
2061:
2062:
2063:
2064:
2065:
2066:
2067:
2068:
2069:
2070:
2071:
2072:
2073:
2074:
2075:
2076:
2077:
2078:
2079:
2080:
2081:
2082:
2083:
2084:
2085:
2086:
2087:
2088:
2089:
2090:
2091:
2092:
2093:
2094:
2095:
2096:
2097:
2098:
2099:
2100:
2101:
2102:
2103:
2104:
2105:
2106:
2107:
2108:
2109:
2110:
2111:
2112:
2113:
2114:
2115:
2116:
2117:
2118:
2119:
2120:
2121:
2122:
2123:
2124:
2125:
2126:
2127:
2128:
2129:
2130:
2131:
2132:
2133:
2134:
2135:
2136:
2137:
2138:
2139:
2140:
2141:
2142:
2143:
2144:
2145:
2146:
2147:
2148:
2149:
2150:
2151:
2152:
2153:
2154:
2155:
2156:
2157:
2158:
2159:
2160:
2161:
2162:
2163:
2164:
2165:
2166:
2167:
2168:
2169:
2170:
2171:
2172:
2173:
2174:
2175:
2176:
2177:
2178:
2179:
2180:
2181:
2182:
2183:
2184:
2185:
2186:
2187:
2188:
2189:
2190:
2191:
2192:
2193:
2194:
2195:
2196:
2197:
2198:
2199:
2200:
2201:
2202:
2203:
2204:
2205:
2206:
2207:
2208:
2209:
2210:
2211:
2212:
2213:
2214:
2215:
2216:
2217:
2218:
2219:
2220:
2221:
2222:
2223:
2224:
2225:
2226:
2227:
2228:
2229:
2230:
2231:
2232:
2233:
2234:
2235:
2236:
2237:
2238:
2239:
2240:
2241:
2242:
2243:
2244:
2245:
2246:
2247:
/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <omni/chrono/date_time.hpp>
#if defined(OMNI_SAFE_DATETIME)
#define OMNI_SAFE_DTTMMTX_FW ,m_mtx()
#define OMNI_DTTM_ALOCK_FW omni::sync::scoped_lock<omni::sync::basic_lock> uuid12345(&this->m_mtx);
#define OMNI_DTTM_OLOCK_FW(o) omni::sync::scoped_lock<omni::sync::basic_lock> uuid54321(&o.m_mtx);
#define OMNI_DTTM_MLOCK_FW this->m_mtx.lock();
#define OMNI_DTTM_ULOCK_FW this->m_mtx.unlock();
#else
#define OMNI_SAFE_DTTMMTX_FW
#define OMNI_DTTM_ALOCK_FW
#define OMNI_DTTM_OLOCK_FW(o)
#define OMNI_DTTM_MLOCK_FW
#define OMNI_DTTM_ULOCK_FW
#endif
// These are local defines
#define OMNI_MAX_MILLIS_FW static_cast<int64_t>(OMNI_MILLISECONDS_TO_10000AD)
#define OMNI_MAX_TICKS_FW OMNI_TICKS_TO_10000AD
#define OMNI_TS_NULL_OFF_FW omni::chrono::time_span::min_value()
#define OMNI_MAX_DATE_OFFSET_FW 504000000000 // OMNI_TICKS_PER_HOUR * 14
#define OMNI_MIN_DATE_OFFSET_FW -OMNI_MAX_DATE_OFFSET_FW
#define OMNI_DATE_ERA_FW "A.D."
#define OMNI_DATE_ERA_ABBR_FW "AD"
#define OMNI_DATE_FORMAT_INFO_AM_FW "AM"
#define OMNI_DATE_FORMAT_INFO_PM_FW "PM"
#define OMNI_DATE_ZULU_NAME_FW "Z"
#define OMNI_DATE_DATA_HXX_FW
#include <omni/xx/date_data.hxx>
#undef OMNI_DATE_DATA_HXX_FW
static std::string omni_date_time_format_day_of_week(int32_t day_of_week, int32_t repeat)
{
if (repeat == 3) {
return omni::cstring::to_title_case(
omni::chrono::day_of_week::get_abbreviated_name(static_cast<omni::chrono::day_of_week::enum_t>(day_of_week))
);
}
return omni::cstring::to_title_case(
omni::chrono::day_of_week::to_string(static_cast<omni::chrono::day_of_week::enum_t>(day_of_week))
);
}
static std::string omni_date_time_format_month(int32_t month, int32_t repeat)
{
if (repeat == 3) {
return omni::cstring::to_title_case(
omni::chrono::month_of_year::get_abbreviated_name(static_cast<omni::chrono::month_of_year::enum_t>(month))
);
}
return omni::cstring::to_title_case(
omni::chrono::month_of_year::to_string(static_cast<omni::chrono::month_of_year::enum_t>(month))
);
}
// The pos should point to a quote character. This method will get the std::string enclosed by the quote character.
static int32_t omni_date_time_format_parse_quote_str(const std::string& format, int32_t pos, std::stringstream& result)
{
// DEV_NOTE: pos will be the index of the quote character in the 'format' string.
int32_t begin = pos;
char quote = format[static_cast<std::size_t>(pos++)]; // Get the character used to quote the following string.
bool found = false;
char next;
while (static_cast<std::size_t>(pos) < format.size()) {
next = format[static_cast<std::size_t>(pos++)];
if (next == quote) {
found = true;
break;
} else if (next == '\\') {
// The following are used to support escaped character.
// Escaped character is also supported in the quoted string.
// Therefore, someone can use a format like "'minute:' mm\"" to display:
// minute: 45"
// because the second double quote is escaped.
if (static_cast<std::size_t>(pos) < format.size()) {
result << format[static_cast<std::size_t>(pos++)];
} else {
// This means that '\' is at the end of the formatting string.
OMNI_ERR_RETV_FW("Invalid string format
", omni::exceptions::invalid_string_format(), std::string())
}
} else {
result << next;
}
}
if (!found) {
// Here we can't find the matching quote.
OMNI_ERR_RETV_FW("Invalid string format: bad quote
", omni::exceptions::invalid_string_format(), std::string())
}
// Return the character count including the begin/end quote characters and enclosed string.
return (pos - begin);
}
/*
Get the next character at the index of 'pos' in the 'format' string.
Return value of -1 means 'pos' is already at the end of the 'format' string.
Otherwise, return value is the int32_t value of the next character.
*/
static int32_t omni_date_time_format_parse_next_char(const std::string& format, int32_t pos)
{
if (static_cast<std::size_t>(pos) >= format.size() - 1) {
return -1;
}
return static_cast<int32_t>(format[static_cast<std::size_t>(pos+1)]);
}
static void omni_date_time_format_digits(std::stringstream& output, int32_t value, int32_t len, bool override_length_limit)
{
// Limit the use of this function to be two-digits, so that we have the same behaviour as RTM bits.
if (!override_length_limit && len > 2) {
len = 2;
}
char* buffer = new char[16];
char* p = buffer + 16;
int32_t n = value;
do {
*--p = static_cast<char>(n % 10 + '0');
n /= 10;
} while ((n != 0) && (p > buffer));
/*
If the repeat count is greater than 0, we're trying
to emulate the "00" format, so we have to prepend
a zero if the string only has one character.
*/
int32_t digits = static_cast<int32_t>(buffer + 16 - p);
while ((digits < len) && (p > buffer)) {
*--p = '0';
++digits;
}
for (n = 0; n < digits; ++n) {
output << *p;
++p;
}
delete[] buffer;
}
/*
FORMAT the positive integer value to a std::string and prefix with assigned
length of leading zero.
Parameters:
value: The value to format
len: The maximum length for leading zero.
If the digits of the value is greater than len, no leading zero is added.
Notes:
The function can format to Int32.MaxValue.
*/
static void omni_date_time_format_digits(std::stringstream& output, int32_t value, int32_t len)
{
omni_date_time_format_digits(output, value, len, false);
}
static int32_t omni_date_time_format_parse_repeat_pattern(const std::string& format, int32_t pos, char pattern)
{
int32_t index = pos + 1;
while ((static_cast<std::size_t>(index) < format.size()) && (format[static_cast<std::size_t>(index)] == pattern)) {
++index;
}
return (index - pos);
}
static bool omni_date_time_internal_offset_from_utc(double* offset)
{
bool is_dst = false;
#if defined(OMNI_OS_WIN)
TIME_ZONE_INFORMATION tz_info;
DWORD err = ::GetTimeZoneInformation(&tz_info);
is_dst = (err == TIME_ZONE_ID_DAYLIGHT);
if (err == TIME_ZONE_ID_INVALID) {
OMNI_ERRV_RETV_FW("An error occurred getting the time zone info: ", OMNI_GLE, omni::exceptions::clock_exception(OMNI_GLE), false)
}
FILETIME utc, curr;
::GetSystemTimeAsFileTime(&utc);
SYSTEMTIME local;
::GetLocalTime(&local);
if (::SystemTimeToFileTime(&local, &curr) == 0) {
OMNI_ERRV_RETV_FW("An error occurred getting the time zone info: ", OMNI_GLE, omni::exceptions::clock_exception(OMNI_GLE), false)
}
*offset = (tz_info.Bias * 60);
if (is_dst) {
*offset -= 3600;
if (::CompareFileTime(&curr, &utc) < 0) {
*offset = -*offset;
}
}
#else
time_t curr;
if (::time(&curr) == static_cast<time_t>(-1)) {
OMNI_ERRV_RETV_FW("An error occurred getting the time zone info: ", OMNI_GLE, omni::exceptions::clock_exception(OMNI_GLE), false)
}
struct tm* timeinfo = ::gmtime(&curr);
if (timeinfo == NULL) {
OMNI_ERRV_RETV_FW("An error occurred getting the time zone info: ", OMNI_GLE, omni::exceptions::clock_exception(OMNI_GLE), false)
}
time_t utc = ::mktime(timeinfo);
if (utc == static_cast<time_t>(-1)) {
OMNI_ERRV_RETV_FW("An error occurred getting the time zone info: ", OMNI_GLE, omni::exceptions::clock_exception(OMNI_GLE), false)
}
timeinfo = ::localtime(&curr);
if (timeinfo == NULL) {
OMNI_ERRV_RETV_FW("An error occurred getting the time zone info: ", OMNI_GLE, omni::exceptions::clock_exception(OMNI_GLE), false)
}
time_t local = ::mktime(timeinfo);
if (local == static_cast<time_t>(-1)) {
OMNI_ERRV_RETV_FW("An error occurred getting the time zone info: ", OMNI_GLE, omni::exceptions::clock_exception(OMNI_GLE), false)
}
*offset = ::difftime(local, utc);
if (timeinfo->tm_isdst) {
// if DST subtract 1 hour. If offset < 0, we need to "add" to have it subtract
if (*offset > 0) {
*offset -= 3600;
} else {
*offset += 3600;
}
is_dst = true;
}
#endif
return is_dst;
}
// output the 'z' family of formats, which output a the offset from UTC, e.g. "-07:30"
static
void omni_date_time_format_customized_timezone(
const omni::chrono::date_time& dt,
const std::string& format, int32_t token_len,
bool time_only, std::stringstream& result)
{
omni::chrono::time_span offset;
OMNI_UNUSED(format);
// No offset. The instance is a DateTime and the output should be the local time zone
if (time_only && dt.ticks() <
OMNI_TICKS_PER_DAY) {
// For time only format and a time only input, the time offset on 0001/01/01 is less
// accurate than the system's current offset because of daylight saving time.
double offset_utc =
0;
omni_date_time_internal_offset_from_utc(&offset_utc);
offset =
static_cast<omni::chrono::time_span::span_t>(offset_utc *
OMNI_TICKS_PER_SECOND);
}
else if (dt.kind() ==
omni::chrono::date_time_kind::UTC) {
offset = omni::chrono::time_span::zero();
}
else {
double offset_utc =
0;
omni_date_time_internal_offset_from_utc(&offset_utc);
offset =
static_cast<omni::chrono::time_span::span_t>(offset_utc *
OMNI_TICKS_PER_SECOND);
}
if (offset >= omni::chrono::time_span::zero()) {
result <<
'+';
}
else {
result <<
'-';
// get a positive offset, so that you don't need a separate code path for the negative numbers.
offset = offset.negate();
}
if (token_len <=
1) {
// 'z' format e.g "-7"
result << offset.hours();
}
else {
// 'zz' or longer format e.g "-07"
if (offset.hours() <
10) {
result << "
0";
}
result << offset.hours();
if (token_len >= 3) {
// 'zzz*' or longer format e.g "-07:30"
result << ":
";
if (offset.minutes() < 10) {
result << "0";
}
result << offset.minutes();
}
}
}
// output the 'K' format, which is for round-tripping the data
static void omni_date_time_format_customized_roundtrip_timezone(const omni::chrono::date_time& dt, std::stringstream& result)
{
/*
The objective of this format is to round trip the data in the type
For DateTime it should round-trip the Kind value and preserve the time zone.
DateTimeOffset instance, it should do so by using the time zone.
*/
omni::chrono::time_span offset;
// source is a date time, so behaviour depends on the kind.
if (dt.kind() == omni::chrono::date_time_kind::LOCAL) {
// This should output the local offset, e.g. "-07:30"
double offset_utc =
0;
omni_date_time_internal_offset_from_utc(&offset_utc);
offset = omni::chrono::time_span::from_seconds(offset_utc);
}
else if (dt.kind() ==
omni::chrono::date_time_kind::UTC) {
// The 'Z' constant is a marker for a UTC date
result << OMNI_DATE_ZULU_NAME_FW;
}
if (offset >= omni::chrono::time_span::zero()) {
result <<
'+';
}
else {
result <<
'-';
// get a positive offset, so that you don't need a separate code path for the negative numbers.
offset = offset.negate();
}
omni::chrono::time_span::span_t hours = offset.hours();
omni::chrono::time_span::span_t minutes = offset.minutes();
if (hours <
10) {
result << "
0";
}
result << hours;
result << ":
";
if (minutes < 10) {
result << "0";
}
result << minutes;
}
static std::string omni_date_time_format_customized(const omni::chrono::date_time& dt_val, const std::string& format)
{
// the default is `M/d/yyyy h:mm:ss tt`
std::stringstream result;
// This is a flag to indicate if we are formatting hour/minute/second only.
bool time_only = true;
int32_t i = 0, token_len = 0, hour12 = 0;
int32_t month = dt_val.month();
int32_t year = dt_val.year();
int32_t next_char;
while (static_cast<std::size_t>(i) < format.size()) {
char ch = format[static_cast<std::size_t>(i)];
std::stringstream enquoted_str;
switch (ch) {
case 'g':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
result << OMNI_DATE_ERA_FW;
break;
case 'h':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
hour12 = dt_val.hour() % 12;
if (hour12 == 0) {
hour12 = 12;
}
omni_date_time_format_digits(result, hour12, token_len);
break;
case 'H':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
omni_date_time_format_digits(result, dt_val.hour(), token_len);
break;
case 'm':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
omni_date_time_format_digits(result, dt_val.minute(), token_len);
break;
case 's':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
omni_date_time_format_digits(result, dt_val.second(), token_len);
break;
case 'f': case 'F':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
if (token_len <= 7) { // 7 = MAX_SECONDS_FRACTION_DIGIT
// const std::string fixed_num_formats[] = { "0", "00", "000", "0000", "00000", "000000", "0000000" };
int64_t fraction =
static_cast<int64_t>(dt_val.ticks() %
OMNI_TICKS_PER_SECOND);
fraction = fraction /
static_cast<int64_t>(
std::pow(
static_cast<
double>(
10),
static_cast<
double>(
7 - token_len)));
if (ch ==
'f') {
result <<
omni::cstring::pad_left(
omni::cstring::to_string(fraction),
'0',
static_cast<
std::size_t>(token_len));
}
else {
int32_t effective_digits = token_len;
while (effective_digits >
0) {
if (fraction %
10 ==
0) {
fraction = fraction /
10;
--effective_digits;
}
else {
break;
}
}
if (effective_digits >
0) {
result <<
omni::cstring::pad_left(
omni::cstring::to_string(fraction),
'0',
static_cast<
std::size_t>(effective_digits -
1));
}
else {
// No fraction to emit, so see if we should remove decimal also.
if (result.str().size() >
0 && result.str()[result.str().size() -
1] ==
'.') {
std::string str = result.str();
result.str(str.substr(
0, str.size() -
1));
}
}
}
}
else {
OMNI_ERR_RETV_FW("Invalid string format
", omni::exceptions::invalid_string_format(), std::string())
}
break;
case 't':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
if (token_len == 1) {
result << (dt_val.hour() < 12 ? "A
" : "P
");
} else {
result << (dt_val.hour() < 12 ? OMNI_DATE_FORMAT_INFO_AM_FW : OMNI_DATE_FORMAT_INFO_PM_FW);
}
break;
case 'd':
/*
token_len == 1 : Day of month as digits with no leading zero.
token_len == 2 : Day of month as digits with leading zero for single-digit months.
token_len == 3 : Day of week as a three-letter abbreviation.
token_len >= 4 : Day of week as its full name.
*/
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
if (token_len <= 2) {
omni_date_time_format_digits(result, dt_val.day(), token_len);
} else {
result << (omni_date_time_format_day_of_week(dt_val.day_of_week(), token_len));
}
time_only = false;
break;
case 'M':
/*
token_len == 1 : Month as digits with no leading zero.
token_len == 2 : Month as digits with leading zero for single-digit months.
token_len == 3 : Month as a three-letter abbreviation.
token_len >= 4 : Month as its full name.
*/
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
if (token_len <= 2) {
omni_date_time_format_digits(result, month, token_len);
} else {
result << (omni_date_time_format_month(month, token_len));
}
time_only = false;
break;
case 'y':
/*
Notes about OS behaviour:
y: Always print (year % 100). No leading zero.
yy: Always print (year % 100) with leading zero.
yyy/yyyy/yyyyy/... : Print year value. No leading zero.
*/
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
if (token_len <= 2) {
omni_date_time_format_digits(result, year % 100, token_len);
} else {
// std::string fmtPattern = "D" + token_len; <- C# format D means decimal (e.g. 12345)
// result << (year.ToString(fmtPattern, CultureInfo.InvariantCulture));
result <<
omni::cstring::pad_left(
omni::cstring::to_string(year),
'0',
static_cast<
std::size_t>(token_len));
}
time_only =
false;
break;
case 'z':
token_len = omni_date_time_format_parse_repeat_pattern(format, i, ch);
omni_date_time_format_customized_timezone(dt_val, format, token_len, time_only, result);
break;
case 'K':
token_len =
1;
omni_date_time_format_customized_roundtrip_timezone(dt_val, result);
break;
case ':':
result << ":
";
token_len = 1;
break;
case '/':
result << "/
";
token_len = 1;
break;
case '\'': case '\"':
token_len = omni_date_time_format_parse_quote_str(format, i, enquoted_str);
result << enquoted_str.str();
break;
case '%':
/*
Optional format character.
For example, format std::string "%d" will print day of month
without leading zero. Most of the cases, "%" can be ignored.
*/
next_char = omni_date_time_format_parse_next_char(format, i);
// next_char will be -1 if we already reach the end of the format string. Besides, we will not allow "%%" appear in the pattern.
if (next_char >=
0 && next_char !=
static_cast<int32_t>('%')) {
result << (omni_date_time_format_customized(dt_val,
omni::string_util::to_string(
static_cast<
char>(next_char))));
token_len =
2;
}
else {
// This means that '%' is at the end of the format std::string or "%%" appears in the format string.
OMNI_ERR_RETV_FW("Invalid string format
", omni::exceptions::invalid_string_format(), std::string())
}
break;
case '\\':
/*
Escaped character. Can be used to insert character into the format string.
For example, "\d" will insert the character 'd' into the string.
DEV_NOTE : we can remove this format character if we enforce the enforced quote character rule.
That is, we ask everyone to use single quote or double quote to insert characters,
then we can remove this character.
*/
next_char = omni_date_time_format_parse_next_char(format, i);
if (next_char >= 0) {
result << ((static_cast<char>(next_char)));
token_len = 2;
} else {
// This means that '\' is at the end of the formatting string.
OMNI_ERR_RETV_FW("Invalid string format
", omni::exceptions::invalid_string_format(), std::string())
}
break;
default:
/*
DEV_NOTE : we can remove this rule if we enforce the enforced quote character rule.
That is, if we ask everyone to use single quote or double quote to insert characters,
then we can remove this default block.
*/
result << ch;
token_len = 1;
break;
}
i += token_len;
}
return result.str();
}
/*
// Formats
invariant.saShortDates = new String[] { "MM/dd/yyyy", "yyyy-MM-dd" }; // short date format
invariant.saLongDates = new String[] { "dddd, dd MMMM yyyy"}; // long date format
invariant.saYearMonths = new String[] { "yyyy MMMM" }; // year month format
invariant.sMonthDay = "MMMM dd"; // Month day pattern
invariant.sAM1159 = "AM"; // AM designator
invariant.sPM2359 = "PM"; // PM designator
invariant.saLongTimes = new String[] { "HH:mm:ss" }; // time format
invariant.saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
invariant.saDurationFormats = new String[] { "HH:mm:ss" }; // time duration format
internal const String rfc1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
// The sortable pattern is based on ISO 8601.
internal const String sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
internal const String universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
internal const String RoundtripFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK";
internal const String RoundtripDateTimeUnfixed = "yyyy'-'MM'-'ddTHH':'mm':'ss zzz";
*/
static std::string omni_date_time_get_real_format(char format)
{
switch (format) {
case 'd': // Short Date
return "M/d/yyyy
"; // "yyyy-MM-dd" for other "calendars"
case 'D':
// Long Date
return "dddd, MMMM d, yyyy
";
case 'f': // Full (long date + short time)
return "dddd, MMMM d, yyyy h:mm tt
";
case 'F': // Full (long date + long time)
return "dddd, MMMM d, yyyy h:mm:ss tt
";
case 'g': // General (short date + short time)
return "M/d/yyyy h:mm
";
case 'G': // General (short date + long time)
return "M/d/yyyy h:mm:ss tt
";
case 'm': case 'M': // Month/Day Date
return "MMMM d
";
case 'o': case 'O': // RoundtripFormat;
return "yyyy
'-'MM
'-'dd
'T'HH
':'mm
':'ss.fffffffK
";
case 'r': case 'R': // RFC 1123 Standard
return "ddd, dd MMM yyyy HH
':'mm
':'ss 'GMT'
";
case 's': // Sortable without Time Zone Info
return "yyyy
'-'MM
'-'dd
'T'HH
':'mm
':'ss
";
case 't': // Short Time
return "h:mm tt
";
case 'T': // Long Time
return "h:mm:ss tt
";
case 'u': // Universal with Sortable format
return "yyyy
'-'MM
'-'dd HH
':'mm
':'ss
'Z'";
case 'U': // Universal with Full (long date + long time) format
return "dddd, MMMM d, yyyy H:mm:ss tt
";
case 'y': case 'Y': // Year/Month Date
return "MMMM yyyy
";
default: // error
OMNI_ERR_RETV_FW("Invalid string format for date_time
", omni::exceptions::invalid_string_format(), std::string())
}
return "";
}
static std::string omni_date_time_format(const omni::chrono::date_time& dt, const std::string& format)
{
std::string new_format = format;
if (new_format.empty()) {
if (dt.ticks() < OMNI_TICKS_PER_DAY) {
// If the time is less than 1 day, consider it as time of day; just print out the short time format.
new_format = "s
";
} else {
new_format = "G
";
}
}
bool is_utc = false;
if (new_format.size() == 1) {
if (new_format[0] == 'U') {
is_utc = true;
}
new_format = omni_date_time_get_real_format(new_format[0]);
}
return is_utc ?
omni_date_time_format_customized(dt.to_universal_time(), new_format) :
omni_date_time_format_customized(dt, new_format);
}
static omni::chrono::date_time omni_chrono_date_time_internal_offset(omni::chrono::date_time& obj, const omni::chrono::span_t& offset)
{
if (offset.ticks() != 0) {
obj += offset;
}
return obj;
}
static uint64_t omni_date_time_internal_get_ticks()
{
#if defined(OMNI_OS_WIN)
FILETIME ft;
::GetSystemTimeAsFileTime(&ft);
ULARGE_INTEGER tm;
tm.LowPart = ft.dwLowDateTime;
tm.HighPart = ft.dwHighDateTime;
return static_cast<uint64_t>(tm.QuadPart) + OMNI_FILE_TIME_OFFSET;
/*
DEV_NOTE: this is from the .NET source
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
// Windows Phone 7.0/7.1 return the ticks up to millisecond, not up to the 100th nanosecond.
long ticksms = ticks / TicksPerMillisecond; <- here .. ticksms now == (ticks / TicksPerMillisecond)
ticks = ticksms * TicksPerMillisecond; <- so right here, doing ticks = ticksms * TicksPerMillisecond
}
this essentially truncates the nanoseconds, but given that Omni will never target Windows Phone, this code is inconsequential
*/
#else
struct timespec tm;
if (::clock_gettime(CLOCK_REALTIME, &tm) != 0) {
OMNI_ERRV_RETV_FW("An error occurred getting the clock time: ", errno, omni::exceptions::clock_exception(errno), false)
}
return static_cast<uint64_t>(
static_cast<uint64_t>(tm.tv_sec * OMNI_TICKS_PER_SECOND) +
static_cast<uint64_t>((static_cast<double>(tm.tv_nsec) * OMNI_TICKS_PER_NANOSECOND)) +
OMNI_EPOCH_OFFSET
);
#endif
}
static bool omni_date_time_internal_is_leap_year(uint64_t year)
{
return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
}
static bool omni_date_time_internal_check_day_range(uint16_t year, uint16_t month, uint16_t day)
{
/*
DEV_NOTE: the C# version throws an exception for Julian days under 1/1/3 .. we'll just return false
*/
if ((year == 1) && (month == 1) && (day < 3)) {
return false;
}
if ((month < 1) || (month > 12) || (day == 0) || (day > 32)) {
// only Jan-Dec and there are not months with 32 days (or 0)
return false;
}
/*
DEV_NOTE: the C# version throws an exception for invalid day range, we'll just return false
*/
if (omni_date_time_internal_is_leap_year(year)) {
// leap year
return day <= (omni::chrono::DAYS_TO_MONTH_366[month] - omni::chrono::DAYS_TO_MONTH_366[month - 1]);
} else {
return day <= (omni::chrono::DAYS_TO_MONTH_365[month] - omni::chrono::DAYS_TO_MONTH_365[month - 1]);
}
return false;
}
// --- start private ctors ---
// not 'user' accessible as it's used to construct empty (min) DT objects
omni::chrono::date_time::date_time() :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(uint64_t ticks, const char* non_op) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(ticks)
OMNI_SAFE_DTTMMTX_FW
{
OMNI_UNUSED(non_op);
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(bool is_ambiguous_dst, const omni::chrono::date_time_kind& kind, uint64_t ticks, const char* non_op) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
OMNI_UNUSED(non_op);
if (ticks > OMNI_MAX_TICKS_FW) {
OMNI_ERR_FW("Invalid tick count specified", omni::exceptions::invalid_range("Invalid tick count specified"))
}
if (kind != omni::chrono::date_time_kind::LOCAL) {
OMNI_ERR_FW("Invalid enum specified for private constructor", omni::exceptions::invalid_enum())
}
this->m_date = (ticks | (is_ambiguous_dst ? OMNI_DATE_KIND_LOCAL_DST_FW : OMNI_DATE_KIND_LOCAL_FW));
OMNI_D5_FW("created");
}
// --- end private ctors ---
omni::chrono::date_time::date_time(const omni::chrono::date_time& cp) :
OMNI_CPCTOR_FW(cp)
m_date(cp._date_value())
OMNI_SAFE_DTTMMTX_FW
{
OMNI_D5_FW("copied");
}
omni::chrono::date_time::date_time(uint64_t ticks) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
if (ticks > OMNI_MAX_TICKS_FW) {
OMNI_ERR_FW("Invalid tick count specified", omni::exceptions::invalid_range("Invalid tick count specified"))
}
this->m_date = ticks;
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(uint64_t ticks, const omni::chrono::date_time_kind& kind) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
if (ticks > OMNI_MAX_TICKS_FW) {
OMNI_ERR_FW("Invalid tick count specified", omni::exceptions::invalid_range("Invalid tick count specified"))
}
if (!omni::chrono::date_time_kind::is_valid(static_cast<int32_t>(kind.value()))) {
OMNI_ERR_FW("Invalid date kind specified", omni::exceptions::invalid_enum("Invalid date kind specified"))
}
this->m_date = (ticks | (static_cast<uint64_t>(kind.value()) << OMNI_DATE_KIND_SHIFT_FW));
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(uint16_t year, uint16_t month, uint16_t day) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
this->m_date = static_cast<uint64_t>(omni::chrono::date_time::_date_to_ticks(year, month, day));
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
this->m_date = static_cast<uint64_t>(omni::chrono::date_time::_date_to_ticks(year, month, day)) +
static_cast<uint64_t>(omni::chrono::date_time::_time_to_ticks(hour, minute, second));
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, const omni::chrono::date_time_kind& kind) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
if (!omni::chrono::date_time_kind::is_valid(static_cast<int32_t>(kind.value()))) {
OMNI_ERR_FW("Invalid date kind specified", omni::exceptions::invalid_enum("Invalid date kind specified"))
}
this->m_date =
(
(
static_cast<uint64_t>(omni::chrono::date_time::_date_to_ticks(year, month, day)) +
static_cast<uint64_t>(omni::chrono::date_time::_time_to_ticks(hour, minute, second))
) // ticks
| // OR'd
( // with kind
static_cast<uint64_t>(kind.value()) << OMNI_DATE_KIND_SHIFT_FW
)
);
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, uint16_t millisecond) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
if (millisecond >= OMNI_MILLISECONDS_PER_SECOND) {
OMNI_ERR_FW("Invalid milliseconds specified", omni::exceptions::invalid_range("Invalid milliseconds specified"))
}
uint64_t ticks = (
static_cast<uint64_t>(omni::chrono::date_time::_date_to_ticks(year, month, day)) +
static_cast<uint64_t>(omni::chrono::date_time::_time_to_ticks(hour, minute, second))
) + (millisecond * OMNI_TICKS_PER_MILLISECOND);
if (ticks > OMNI_MAX_TICKS_FW) {
OMNI_ERR_FW("Invalid tick count specified", omni::exceptions::invalid_range("Invalid tick count specified"))
}
this->m_date = ticks;
OMNI_D5_FW("created");
}
omni::chrono::date_time::date_time(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, uint16_t millisecond, const omni::chrono::date_time_kind& kind) :
OMNI_CTOR_FW(omni::chrono::date_time)
m_date(0)
OMNI_SAFE_DTTMMTX_FW
{
if (millisecond >= OMNI_MILLISECONDS_PER_SECOND) {
OMNI_ERR_FW("Invalid milliseconds specified", omni::exceptions::invalid_range("Invalid milliseconds specified"))
}
if (!omni::chrono::date_time_kind::is_valid(static_cast<int32_t>(kind.value()))) {
OMNI_ERR_FW("Invalid date kind specified", omni::exceptions::invalid_enum("Invalid date kind specified"))
}
uint64_t ticks = (
static_cast<uint64_t>(omni::chrono::date_time::_date_to_ticks(year, month, day)) +
static_cast<uint64_t>(omni::chrono::date_time::_time_to_ticks(hour, minute, second))
) + (millisecond * OMNI_TICKS_PER_MILLISECOND);
if (ticks > OMNI_MAX_TICKS_FW) {
OMNI_ERR_FW("Invalid tick count specified", omni::exceptions::invalid_range("Invalid tick count specified"))
}
this->m_date = (ticks | (static_cast<uint64_t>(kind.value()) << OMNI_DATE_KIND_SHIFT_FW));
OMNI_D5_FW("created");
}
omni::chrono::date_time::~date_time()
{
OMNI_TRY_FW
OMNI_DTOR_FW
OMNI_CATCH_FW
OMNI_D5_FW("destroyed");
}
omni::chrono::date_time omni::chrono::date_time::add(const omni::chrono::time_span& value) const
{
return this->add_ticks(value.ticks());
}
omni::chrono::date_time omni::chrono::date_time::add_days(double value) const
{
OMNI_DTTM_ALOCK_FW
return this->_add(value, OMNI_MILLISECONDS_PER_DAY);
}
omni::chrono::date_time omni::chrono::date_time::add_hours(double value) const
{
OMNI_DTTM_ALOCK_FW
return this->_add(value, OMNI_MILLISECONDS_PER_HOUR);
}
omni::chrono::date_time omni::chrono::date_time::add_milliseconds(double value) const
{
OMNI_DTTM_ALOCK_FW
return this->_add(value, 1);
}
omni::chrono::date_time omni::chrono::date_time::add_minutes(double value) const
{
OMNI_DTTM_ALOCK_FW
return this->_add(value, OMNI_MILLISECONDS_PER_MINUTE);
}
omni::chrono::date_time omni::chrono::date_time::add_months(int32_t months) const
{
OMNI_DTTM_ALOCK_FW
if ((months < -120000) || (months > 120000)) {
OMNI_ERR_RETV_FW("Invalid months specified", omni::exceptions::invalid_range("Invalid months specified"), omni::chrono::date_time())
}
int64_t y = omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_YEAR_FW);
int64_t m = omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_MONTH_FW);
int64_t d = omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_DAY_FW);
int64_t i = m - 1 + months;
if (i >= 0) {
m = i % 12 + 1;
y = y + i / 12;
} else {
m = 12 + (i + 1) % 12;
y = y + (i - 11) / 12;
}
if (y < 1 || y > OMNI_DATE_MAX_YEAR) {
OMNI_ERR_RETV_FW("Invalid months specified", omni::exceptions::invalid_range("Invalid months specified"), omni::chrono::date_time())
}
int64_t days = omni::chrono::date_time::days_in_month(static_cast<uint16_t>(y), static_cast<uint16_t>(m));
if (d > days) {
d = days;
}
return omni::chrono::date_time(
static_cast<uint64_t>(omni::chrono::date_time::_date_to_ticks(static_cast<uint16_t>(y), static_cast<uint16_t>(m), static_cast<uint16_t>(d)) + (this->_ticks() % OMNI_TICKS_PER_DAY))
| this->_internal_kind()
);
}
omni::chrono::date_time omni::chrono::date_time::add_seconds(double value) const
{
OMNI_DTTM_ALOCK_FW
return this->_add(value, OMNI_MILLISECONDS_PER_SECOND);
}
omni::chrono::date_time omni::chrono::date_time::add_ticks(int64_t value) const
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
if ((value > (OMNI_MAX_TICKS_FW - ticks)) || (value < (-ticks)) ) {
OMNI_ERR_RETV_FW("Invalid ticks specified", omni::exceptions::invalid_range("Invalid ticks specified"), omni::chrono::date_time())
}
return omni::chrono::date_time(static_cast<uint64_t>(ticks + value) | this->_internal_kind());
}
omni::chrono::date_time omni::chrono::date_time::add_years(int16_t value) const
{
if ((value < -10000) || (value > 10000)) {
OMNI_ERR_RETV_FW("Invalid years specified", omni::exceptions::invalid_range("Invalid years specified"), omni::chrono::date_time())
}
return this->add_months(value * 12);
}
bool omni::chrono::date_time::is_dst() const
{
OMNI_DTTM_ALOCK_FW
if (this->_kind() == omni::chrono::date_time_kind::LOCAL_DST) {
return true;
}
/*
DEV_NOTE: The C# way of handling DST (e.g. Getis_dst/CheckIsDst) seems somewhat convoluted and uses
the system's timezone info database to more appropriately get whether a date/time is actually DST.
We're not going "full hog" on the date time class with calendars/zone info etc. right now, so instead
we're going to implement the "lazy-man's DST calculator" that only looks at US times. If the date falls
in a "range" of what the US DST standard is, then we just return true.
There are some carved out exceptions since DST in the US didn't "start" til 1966, but had some odd moments.
--- see notes/comments below
*/
uint16_t year = static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_YEAR_FW));
uint16_t month = static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_MONTH_FW));
uint16_t day = static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_DAY_FW));
if (year < 1966) {
// summer DST to begin on March 31, 1918 (reverting October 27) .. only during this year
if (year == 1918) {
if (((month == 3) && (day == 31)) || ((month > 3) && ((month <= 10) && (day < 27)))) {
// < 27 because it ENDED the 27th, so does not include the 27th
return true;
}
return false;
}
// Feb 9, 1942 -> Sep 30, 1945 == permanent DST
if (((year >= 1942) && (month >= 2) && (day >= 9)) && ((year <= 1945) && (month <= 9) && (day < 30))) {
// < 30 because it ENDED the 30th, so does not include the 30th
return true;
}
return false;
}
// Jan 6, 1974 -> Apr 27, 1975 == permanent DST
if (((year >= 1974) && (month >= 1) && (day >= 6)) && ((year <= 1975) && (month <= 4) && (day < 27))) {
// < 27 because it ENDED the 27th, so does not include the 27th
return true;
}
if (year >= 2007) {
// Starting 2007, DST begins on the second Sunday of March and ends on the first Sunday of November
// Jan, Feb, Dec are NOT part of DST
if ((month <= 2) || (month == 12)) { return false; }
// Apr -> Oct are
if ((month >= 4) && (month <= 10)) { return true; }
// March and November are the "ambiguous" months
} else {
// 1986 - 2006, DST started first Sunday in April and to the last Sunday in October
// 1966 - 1986, DST started last Sunday in April to last Sunday in October
// Jan, Feb, Mar, Nov, Dec are NOT part of DST
if ((month <= 3) || (month >= 11)) { return false; }
// May -> Jul are
if ((month >= 5) && (month <= 7)) { return true; }
// April and October are the "ambiguous" months
}
// dow (day of week): sunday = 0, mon = 1 .. sat = 6
int16_t prev_sun_date =
static_cast<int16_t>(day -
static_cast<
uint16_t>((
this->_ticks() /
OMNI_TICKS_PER_DAY +
1) %
7));
uint16_t hour =
static_cast<
uint16_t>((
this->_ticks() /
OMNI_TICKS_PER_HOUR) %
24);
/*
2AM 3AM 1AM 2AM
| +1 hr | | -1 hr |
| <invalid time> | | <ambiguous time> |
[========== DST ========>)
3AM -starts- DST because at 2, the clock rolls up, so there is no 2AM
1AM is -ambiguous- because at 2 the clock rolls back, so it *could* be 1:30 and -not- DST
*/
if (year >=
2007) {
// Starting 2007, DST begins on the second Sunday of March and ends on the first Sunday of November
// 2nd Sunday in March can be 8th - 14th
if ((month ==
3) && (prev_sun_date >=
8) && (hour >
3)) {
return true;
}
// 1st Sunday in Nov can be 1st - 7th
if ((month ==
11) && (prev_sun_date <=
7)) {
// if OMNI_DATE_TIME_AMBIGUOUS_DST_1AM is defined then DST -stops- at 1am
#if defined(OMNI_DATE_TIME_AMBIGUOUS_DST_1AM)
if (hour <= 1) { return true; }
#else
if (hour == 0) { return true; }
#endif
}
} else if ((year >= 1986) && (year <= 2006)) {
// 1986 - 2006, DST started first Sunday in April and to the last Sunday in October
// 1st Sunday in April can be 1st - 7th
if ((month == 4) && (prev_sun_date <= 7) && (hour > 3)) {
return true;
}
// Last Sunday in Oct can be 25th - 31st
if ((month == 10) && (prev_sun_date >= 25)) {
// if OMNI_DATE_TIME_AMBIGUOUS_DST_1AM is defined then DST -stops- at 1am
#if defined(OMNI_DATE_TIME_AMBIGUOUS_DST_1AM)
if (hour <= 1) { return true; }
#else
if (hour == 0) { return true; }
#endif
}
} else {
// 1966 - 1986, DST started last Sunday in April to last Sunday in October
// Last Sunday in April can be 24th - 30th
if ((month == 4) && (prev_sun_date >= 24) && (hour > 3)) {
return true;
}
// Last Sunday in Oct can be 25th - 31st
if ((month == 10) && (prev_sun_date >= 25)) {
// if OMNI_DATE_TIME_AMBIGUOUS_DST_1AM is defined then DST -stops- at 1am
#if defined(OMNI_DATE_TIME_AMBIGUOUS_DST_1AM)
if (hour <= 1) { return true; }
#else
if (hour == 0) { return true; }
#endif
}
}
return false;
}
bool omni::chrono::date_time::is_ambiguous_dst() const
{
OMNI_DTTM_ALOCK_FW
uint16_t year = static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_YEAR_FW));
uint16_t month = static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_MONTH_FW));
uint16_t day = static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_DAY_FW));
// dow (day of week): sunday = 0, mon = 1 .. sat = 6
int16_t prev_sun_date = static_cast<int16_t>(day - static_cast<uint16_t>((this->_ticks() / OMNI_TICKS_PER_DAY + 1) % 7));
uint16_t hour = static_cast<uint16_t>((this->_ticks() / OMNI_TICKS_PER_HOUR) % 24);
/*
2AM 3AM 1AM 2AM
| +1 hr | | -1 hr |
| <invalid time> | | <ambiguous time> |
[========== DST ========>)
3AM -starts- DST because at 2, the clock rolls up, so there is no 2AM
1AM is -ambiguous- because at 2 the clock rolls back, so it *could* be 1:30 and -not- DST
*/
if (year >= 2007) {
if ((month == 11) && (prev_sun_date <= 7)) {
return ((hour >= 1) && (hour <= 2));
}
} else if ((year >= 1986) && (year <= 2006)) {
if ((month == 10) && (prev_sun_date >= 25)) {
return ((hour >= 1) && (hour <= 2));
}
} else {
if ((month == 10) && (prev_sun_date >= 25)) {
return ((hour >= 1) && (hour <= 2));
}
}
return false;
}
bool omni::chrono::date_time::is_leap_year() const
{
return omni::chrono::date_time::is_leap_year(*this);
}
bool omni::chrono::date_time::is_leap_day() const
{
return omni::chrono::date_time::is_leap_day(*this);
}
int64_t omni::chrono::date_time::to_binary() const
{
if (this->kind() == omni::chrono::date_time_kind::LOCAL) {
/*
Local times need to be adjusted as you move from one time zone to another,
just as they are when serializing in text. As such the format for local times
changes to store the ticks of the UTC time, but with flags that look like a
local date.
To match serialization in text we need to be able to handle cases where
the UTC value would be out of range. Unused parts of the ticks range are
used for this, so that values just past max value are stored just past the
end of the maximum range, and values just below minimum value are stored
at the end of the ticks area, just below 2^62.
*/
omni::chrono::time_span offset(0, 0, static_cast<omni::chrono::time_span::span_t>(omni::chrono::date_time::offset_from_utc()));
int64_t ticks = this->_ticks();
int64_t stored = ticks - offset.ticks();
if (stored < 0) {
stored = OMNI_TICKS_CEILING_FW + stored;
}
return stored | static_cast<int64_t>(OMNI_DATE_LOCAL_MASK_FW);
}
return static_cast<int64_t>(this->m_date);
}
omni::chrono::date_time omni::chrono::date_time::date() const
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
return omni::chrono::date_time(static_cast<uint64_t>(ticks - ticks % OMNI_TICKS_PER_DAY) | this->_internal_kind(), "");
}
// Returns the day-of-month part of this DateTime. The returned value is an integer between 1 and 31.
uint16_t omni::chrono::date_time::day() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_DAY_FW));
}
omni::chrono::day_of_week omni::chrono::date_time::day_of_week() const
{
OMNI_DTTM_ALOCK_FW
return omni::chrono::day_of_week(
static_cast<omni::chrono::day_of_week::enum_t>(
((this->_ticks() / OMNI_TICKS_PER_DAY + 1) % 7)
)
);
}
uint16_t omni::chrono::date_time::day_of_year() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_DAY_OF_YEAR_FW));
}
int32_t omni::chrono::date_time::hash_code() const
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
return static_cast<int32_t>(ticks) ^ static_cast<int32_t>(ticks >> 32);
}
uint16_t omni::chrono::date_time::hour() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>((this->_ticks() / OMNI_TICKS_PER_HOUR) % 24);
}
omni::chrono::date_time_kind omni::chrono::date_time::kind() const
{
OMNI_DTTM_ALOCK_FW
return this->_kind();
}
uint16_t omni::chrono::date_time::millisecond() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>((this->_ticks()/ OMNI_TICKS_PER_MILLISECOND) % 1000);
}
uint16_t omni::chrono::date_time::minute() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>((this->_ticks()/ OMNI_TICKS_PER_MINUTE) % 60);
}
uint16_t omni::chrono::date_time::month() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_MONTH_FW));
}
uint16_t omni::chrono::date_time::second() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>((this->_ticks()/ OMNI_TICKS_PER_SECOND) % 60);
}
uint64_t omni::chrono::date_time::ticks() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint64_t>(this->_ticks());
}
omni::chrono::time_span omni::chrono::date_time::time_of_day() const
{
OMNI_DTTM_ALOCK_FW
return omni::chrono::time_span(this->_ticks() % OMNI_TICKS_PER_DAY);
}
uint16_t omni::chrono::date_time::year() const
{
OMNI_DTTM_ALOCK_FW
return static_cast<uint16_t>(omni::chrono::date_time::_get_date_part(OMNI_DATE_PART_YEAR_FW));
}
omni::chrono::time_span omni::chrono::date_time::utc_offset() const
{
OMNI_DTTM_ALOCK_FW
if (this->_kind() == omni::chrono::date_time_kind::UTC) {
return omni::chrono::time_span::zero();
}
double offset_utc = 0;
omni_date_time_internal_offset_from_utc(&offset_utc);
return omni::chrono::time_span::from_seconds(offset_utc);
}
omni::chrono::time_span omni::chrono::date_time::subtract(const omni::chrono::date_time& value) const
{
OMNI_DTTM_ALOCK_FW
return omni::chrono::time_span(this->_ticks() - value._ticks());
}
omni::chrono::date_time omni::chrono::date_time::subtract(const omni::chrono::time_span& value) const
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
int64_t vticks = value.ticks();
if ((ticks < vticks) || ((ticks - OMNI_MAX_TICKS_FW) > vticks)) {
OMNI_ERR_RETV_FW("Invalid time span specified", omni::exceptions::invalid_range("Invalid time span specified"), omni::chrono::date_time())
}
return omni::chrono::date_time(static_cast<uint64_t>(ticks - vticks) | this->_internal_kind());
}
double omni::chrono::date_time::to_oa_date() const
{
OMNI_DTTM_ALOCK_FW
return this->_ticks_to_oa_date(this->_ticks());
}
uint64_t omni::chrono::date_time::to_file_time() const
{
// Treats the input as local if it is not specified
return this->to_universal_time().to_file_time_utc();
}
uint64_t omni::chrono::date_time::to_file_time_utc() const
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = (
((this->_internal_kind() & OMNI_DATE_LOCAL_MASK_FW) != 0) ?
this->to_universal_time()._ticks() :
this->_ticks()
) - OMNI_FILE_TIME_OFFSET;
if (ticks < 0) {
OMNI_ERR_RETV_FW("Invalid file time specified", omni::exceptions::invalid_range("Invalid file time specified"), 0)
}
return static_cast<uint64_t>(ticks);
}
omni::chrono::date_time omni::chrono::date_time::to_local_time() const
{
OMNI_DTTM_ALOCK_FW
return this->_to_local_time(false);
}
std::string omni::chrono::date_time::to_long_date_string() const
{
OMNI_DTTM_ALOCK_FW
return omni_date_time_format(*this, "D");
}
std::wstring omni::chrono::date_time::to_long_date_wstring() const
{
OMNI_DTTM_ALOCK_FW
return omni::string_util::to_wstring(omni_date_time_format(*this, "D"));
}
std::string omni::chrono::date_time::to_long_time_string() const
{
OMNI_DTTM_ALOCK_FW
return omni_date_time_format(*this, "T");
}
std::wstring omni::chrono::date_time::to_long_time_wstring() const
{
OMNI_DTTM_ALOCK_FW
return omni::string_util::to_wstring(omni_date_time_format(*this, "T"));
}
std::string omni::chrono::date_time::to_short_date_string() const
{
OMNI_DTTM_ALOCK_FW
return omni_date_time_format(*this, "d");
}
std::wstring omni::chrono::date_time::to_short_date_wstring() const
{
OMNI_DTTM_ALOCK_FW
return omni::string_util::to_wstring(omni_date_time_format(*this, "d"));
}
std::string omni::chrono::date_time::to_short_time_string() const
{
OMNI_DTTM_ALOCK_FW
return omni_date_time_format(*this, "t");
}
std::wstring omni::chrono::date_time::to_short_time_wstring() const
{
OMNI_DTTM_ALOCK_FW
return omni::string_util::to_wstring(omni_date_time_format(*this, "t"));
}
std::string omni::chrono::date_time::to_string(const std::string& format) const
{
OMNI_DTTM_ALOCK_FW
return omni_date_time_format(*this, format);
}
std::wstring omni::chrono::date_time::to_wstring(const std::wstring& format) const
{
OMNI_DTTM_ALOCK_FW
return omni::string_util::to_wstring(omni_date_time_format(*this, omni::string_util::to_string(format)));
}
omni::chrono::date_time omni::chrono::date_time::to_universal_time() const
{
if (this->kind() == omni::chrono::date_time_kind::UTC) {
return omni::chrono::date_time(*this);
}
omni::chrono::span_t offset(0, 0, static_cast<omni::chrono::span_t::span_t>(omni::chrono::date_time::offset_from_utc()));
#if defined(OMNI_SAFE_DATETIME)
this->m_mtx.lock();
#endif
omni::chrono::date_time obj(omni::chrono::date_time::specify_kind(*this, omni::chrono::date_time_kind::UTC));
#if defined(OMNI_SAFE_DATETIME)
this->m_mtx.unlock();
#endif
// DEV_NOTE: we negate the offset since we want to get to UTC, and if the offset is
// negative, adding a negative will subtract; instead of using std::abs, negate is quicker
return omni_chrono_date_time_internal_offset(obj, offset.negate());
}
std::string omni::chrono::date_time::to_military_dtg_string() const
{
// DD HH MM SS Z mmm YY
std::string zulu = this->to_string("ddHHmmss");
int64_t offset = this->utc_offset().ticks() / OMNI_TICKS_PER_HOUR;
switch (offset) {
case -12: zulu += "Y"; break;
case -11: zulu += "X"; break;
case -10: zulu += "W"; break;
case -9: zulu += "V"; break;
case -8: zulu += "U"; break;
case -7: zulu += "T"; break;
case -6: zulu += "S"; break;
case -5: zulu += "R"; break;
case -4: zulu += "Q"; break;
case -3: zulu += "P"; break;
case -2: zulu += "O"; break;
case -1: zulu += "N"; break;
case 0: zulu += "Z"; break;
case 1: zulu += "A"; break;
case 2: zulu += "B"; break;
case 3: zulu += "C"; break;
case 4: zulu += "D"; break;
case 5: zulu += "E"; break;
case 6: zulu += "F"; break;
case 7: zulu += "G"; break;
case 8: zulu += "H"; break;
case 9: zulu += "I"; break;
case 10: zulu += "K"; break;
case 11: zulu += "L"; break;
case 12: zulu += "M"; break;
default: zulu += " "; break;
}
zulu += omni::chrono::month_of_year::get_abbreviated_name(static_cast<omni::chrono::month_of_year::enum_t>(this->month())) + this->to_string("yy");
return zulu;
}
std::wstring omni::chrono::date_time::to_military_dtg_wstring() const
{
// DD HH MM SS Z mmm YY
std::wstring zulu = this->to_wstring(L"ddHHmmss");
int64_t offset = this->utc_offset().ticks() / OMNI_TICKS_PER_HOUR;
switch (offset) {
case -12: zulu += L"Y"; break;
case -11: zulu += L"X"; break;
case -10: zulu += L"W"; break;
case -9: zulu += L"V"; break;
case -8: zulu += L"U"; break;
case -7: zulu += L"T"; break;
case -6: zulu += L"S"; break;
case -5: zulu += L"R"; break;
case -4: zulu += L"Q"; break;
case -3: zulu += L"P"; break;
case -2: zulu += L"O"; break;
case -1: zulu += L"N"; break;
case 0: zulu += L"Z"; break;
case 1: zulu += L"A"; break;
case 2: zulu += L"B"; break;
case 3: zulu += L"C"; break;
case 4: zulu += L"D"; break;
case 5: zulu += L"E"; break;
case 6: zulu += L"F"; break;
case 7: zulu += L"G"; break;
case 8: zulu += L"H"; break;
case 9: zulu += L"I"; break;
case 10: zulu += L"K"; break;
case 11: zulu += L"L"; break;
case 12: zulu += L"M"; break;
default: zulu += L" "; break;
}
zulu += omni::chrono::month_of_year::get_abbreviated_wname(static_cast<omni::chrono::month_of_year::enum_t>(this->month())) + this->to_wstring(L"yy");
return zulu;
}
void omni::chrono::date_time::swap(omni::chrono::date_time& other)
{
OMNI_DTTM_ALOCK_FW
OMNI_DTTM_OLOCK_FW(other)
OMNI_XOR_SWAP(this->m_date, other.m_date);
}
omni::string_t omni::chrono::date_time::to_string_t() const
{
#if defined(OMNI_UNICODE)
return this->to_wstring();
#else
return this->to_string();
#endif
}
std::string omni::chrono::date_time::to_string() const
{
return this->to_string(std::string());
}
std::wstring omni::chrono::date_time::to_wstring() const
{
return this->to_wstring(std::wstring());
}
omni::chrono::date_time& omni::chrono::date_time::operator=(const omni::chrono::date_time& other)
{
if (this != &other) {
OMNI_DTTM_ALOCK_FW
OMNI_DTTM_OLOCK_FW(other)
OMNI_ASSIGN_FW(other)
this->m_date = other.m_date;
}
return *this;
}
omni::chrono::date_time omni::chrono::date_time::operator+(const omni::chrono::time_span& span)
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
int64_t vticks = span.ticks();
if ((vticks > (OMNI_MAX_TICKS_FW - ticks)) || (vticks < (0 - ticks))) {
OMNI_ERR_RETV_FW("Invalid OLE date specified", omni::exceptions::invalid_range("Invalid OLE date specified"), *this)
}
return omni::chrono::date_time(static_cast<uint64_t>(ticks + vticks) | this->_internal_kind());
}
omni::chrono::date_time omni::chrono::date_time::operator-(const omni::chrono::time_span& span)
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
int64_t vticks = span.ticks();
if ((ticks < vticks) || ((ticks - OMNI_MAX_TICKS_FW) > vticks)) {
OMNI_ERR_RETV_FW("Invalid OLE date specified", omni::exceptions::invalid_range("Invalid OLE date specified"), *this)
}
return omni::chrono::date_time(static_cast<uint64_t>(ticks - vticks) | this->_internal_kind());
}
omni::chrono::date_time& omni::chrono::date_time::operator+=(const omni::chrono::time_span& span)
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
int64_t vticks = span.ticks();
if ((vticks > (OMNI_MAX_TICKS_FW - ticks)) || (vticks < (0 - ticks))) {
OMNI_ERR_RETV_FW("Invalid OLE date specified", omni::exceptions::invalid_range("Invalid OLE date specified"), *this)
}
this->m_date = (static_cast<uint64_t>(ticks + vticks) | this->_internal_kind());
return *this;
}
omni::chrono::date_time& omni::chrono::date_time::operator-=(const omni::chrono::time_span& span)
{
OMNI_DTTM_ALOCK_FW
int64_t ticks = this->_ticks();
int64_t vticks = span.ticks();
if ((ticks < vticks) || ((ticks - OMNI_MAX_TICKS_FW) > vticks)) {
OMNI_ERR_RETV_FW("Invalid OLE date specified", omni::exceptions::invalid_range("Invalid OLE date specified"), *this)
}
this->m_date = (static_cast<uint64_t>(ticks - vticks) | this->_internal_kind());
return *this;
}
omni::chrono::time_span omni::chrono::date_time::operator-(const omni::chrono::date_time& other)
{
OMNI_DTTM_ALOCK_FW
return omni::chrono::time_span(this->_ticks() - static_cast<int64_t>(other.ticks()));
}
omni::chrono::time_span omni::chrono::date_time::operator+(const omni::chrono::date_time& other)
{
OMNI_DTTM_ALOCK_FW
return omni::chrono::time_span(this->_ticks() + static_cast<int64_t>(other.ticks()));
}
bool omni::chrono::date_time::operator==(const omni::chrono::date_time& other) const
{
if (this == &other) { return true; }
OMNI_DTTM_ALOCK_FW
OMNI_DTTM_OLOCK_FW(other)
return (
this->m_date == other.m_date
)
OMNI_EQUAL_FW(other);
}
bool omni::chrono::date_time::operator!=(const omni::chrono::date_time& other) const
{
return !(*this == other);
}
bool omni::chrono::date_time::operator<(const omni::chrono::date_time& other) const
{
if (this == &other) { return false; }
OMNI_DTTM_ALOCK_FW
OMNI_DTTM_OLOCK_FW(other)
return (this->m_date < other.m_date);
}
bool omni::chrono::date_time::operator<=(const omni::chrono::date_time& other) const
{
if (this == &other) { return true; }
OMNI_DTTM_ALOCK_FW
OMNI_DTTM_OLOCK_FW(other)
return (this->m_date <= other.m_date);
}
bool omni::chrono::date_time::operator>(const omni::chrono::date_time& other) const
{
if (this == &other) { return false; }
OMNI_DTTM_ALOCK_FW
OMNI_DTTM_OLOCK_FW(other)
return (this->m_date > other.m_date);
}
bool omni::chrono::date_time::operator>=(const omni::chrono::date_time& other) const
{
if (this == &other) { return true; }
OMNI_DTTM_ALOCK_FW
OMNI_DTTM_OLOCK_FW(other)
return (this->m_date >= other.m_date);
}
// -- start private methods --
omni::chrono::date_time omni::chrono::date_time::_add(double value, int64_t scale) const
{
int64_t millis = static_cast<int64_t>(
(value * static_cast<double>(scale)) + ((value >= 0.0) ? 0.5 : -0.5)
);
if ((millis <= -OMNI_MAX_MILLIS_FW) || (millis >= OMNI_MAX_MILLIS_FW)) {
OMNI_ERR_RETV_FW("Invalid value/scale specified", omni::exceptions::invalid_range("Invalid value/scale specified"), omni::chrono::date_time())
}
return this->add_ticks(millis * OMNI_TICKS_PER_MILLISECOND);
}
omni::chrono::date_time_kind omni::chrono::date_time::_kind() const
{
switch (this->_internal_kind()) {
case OMNI_DATE_KIND_UNSPECIFIED_FW:
return omni::chrono::date_time_kind::UNSPECIFIED;
case OMNI_DATE_KIND_UTC_FW:
return omni::chrono::date_time_kind::UTC;
case OMNI_DATE_KIND_LOCAL_DST_FW:
return omni::chrono::date_time_kind::LOCAL_DST;
default: break;
}
return omni::chrono::date_time_kind::LOCAL;
}
int64_t omni::chrono::date_time::_to_binary_raw() const
{
return static_cast<int64_t>(this->m_date);
}
int64_t omni::chrono::date_time::_get_date_part(uint16_t part) const
{
#if defined(OMNI_NO_CONSTS)
const int32_t DT365[] = OMNI_DAYS_TO_MONTH_365;
const int32_t DT366[] = OMNI_DAYS_TO_MONTH_366;
#endif
const int32_t* days = OMNI_NULL_PTR;
int64_t n, y400, y100, y4, y1, m;
int64_t ticks = this->_ticks();
// n = number of days since 1/1/0001
n = (ticks / OMNI_TICKS_PER_DAY);
// y400 = number of whole 400-year periods since 1/1/0001
y400 = n / OMNI_DAYS_PER_400_YEARS;
// n = day number within 400-year period
n -= y400 * OMNI_DAYS_PER_400_YEARS;
// y100 = number of whole 100-year periods within 400-year period
y100 = n / OMNI_DAYS_PER_100_YEARS;
// Last 100-year period has an extra day, so decrement result if 4
if (y100 == 4) { y100 = 3; }
// n = day number within 100-year period
n -= y100 * OMNI_DAYS_PER_100_YEARS;
// y4 = number of whole 4-year periods within 100-year period
y4 = n / OMNI_DAYS_PER_4_YEARS;
// n = day number within 4-year period
n -= y4 * OMNI_DAYS_PER_4_YEARS;
// y1 = number of whole years within 4-year period
y1 = n / OMNI_DAYS_PER_YEAR;
// Last year has an extra day, so decrement result if 4
if (y1 == 4) y1 = 3;
// If year was requested, compute and return it
if (part == OMNI_DATE_PART_YEAR_FW) {
return (y400 * 400) + (y100 * 100) + (y4 * 4) + y1 + 1;
}
// n = day number within year
n -= y1 * OMNI_DAYS_PER_YEAR;
// If day-of-year was requested, return it
if (part == OMNI_DATE_PART_DAY_OF_YEAR_FW) {
return n + 1;
}
// Leap year calculation looks different from IsLeapYear since y1, y4,
// and y100 are relative to year 1, not year 0
m = (n >> 5) + 1;
// All months have less than 32 days, so n >> 5 is a good conservative
// estimate for the month
// m = 1-based month number
if ((y1 == 3) && (y4 != 24 || y100 == 3)) {
#if defined(OMNI_NO_CONSTS)
days = &DT366[0];
#else
days = &omni::chrono::DAYS_TO_MONTH_366[0];
#endif
} else {
#if defined(OMNI_NO_CONSTS)
days = &DT365[0];
#else
days = &omni::chrono::DAYS_TO_MONTH_365[0];
#endif
}
while (n >= days[m]) {
m++;
}
// If month was requested, return it
if (part == OMNI_DATE_PART_MONTH_FW) {
return m;
}
// Return 1-based day-of-month
return n - days[m - 1] + 1;
}
omni::chrono::date_time omni::chrono::date_time::_to_local_time(bool throw_on_overflow) const
{
//OMNI_DTTM_ALOCK_FW
if (this->kind() == omni::chrono::date_time_kind::LOCAL) {
return omni::chrono::date_time(*this);
}
// bool is_dst = false;
bool is_ambiguous_local_dst = false;
int64_t offset = (omni::chrono::span_t(0, 0, static_cast<omni::chrono::span_t::span_t>(omni::chrono::date_time::offset_from_utc()))).ticks();
int64_t tick = this->_ticks() + offset;
if (tick > OMNI_MAX_TICKS_FW) {
if (throw_on_overflow) {
OMNI_ERR_RETV_FW("Invalid ticks for local time", omni::exceptions::invalid_range("Invalid ticks for local time"), omni::chrono::date_time())
} else {
return omni::chrono::date_time(OMNI_MAX_TICKS_FW, omni::chrono::date_time_kind::LOCAL);
}
}
if (tick < 0) {
if (throw_on_overflow) {
OMNI_ERR_RETV_FW("Invalid local time", omni::exceptions::invalid_range("Invalid local time"), omni::chrono::date_time())
} else {
return omni::chrono::date_time(0, omni::chrono::date_time_kind::LOCAL);
}
}
return omni::chrono::date_time(is_ambiguous_local_dst, omni::chrono::date_time_kind::LOCAL, static_cast<uint64_t>(tick), "");
}
// -- start static methods --
uint16_t omni::chrono::date_time::days_in_month(uint16_t year, uint16_t month)
{
if ((month < 1) || (month > 12)) {
OMNI_ERR_RETV_FW("Invalid month specified", omni::exceptions::invalid_range("Invalid month specified"), omni::chrono::date_time())
}
#if defined(OMNI_NO_CONSTS)
if (omni::chrono::is_leap_year(year)) {
// check the year argument
const int32_t d366[] = OMNI_DAYS_TO_MONTH_366;
return d366[month] - d366[month - 1];
}
const int32_t d365[] = OMNI_DAYS_TO_MONTH_365;
return d365[month] - d365[month - 1];
#else
if (omni::chrono::is_leap_year(year)) {
// check the year argument
return static_cast<uint16_t>(omni::chrono::DAYS_TO_MONTH_366[month] - omni::chrono::DAYS_TO_MONTH_366[month - 1]);
}
return static_cast<uint16_t>(omni::chrono::DAYS_TO_MONTH_365[month] - omni::chrono::DAYS_TO_MONTH_365[month - 1]);
#endif
}
omni::chrono::date_time omni::chrono::date_time::from_binary(int64_t date_data)
{
if ((date_data & static_cast<int64_t>(OMNI_DATE_LOCAL_MASK_FW)) != 0) {
/*
Local times need to be adjusted as you move from one time zone to another,
just as they are when serializing in text. As such the format for local times
changes to store the ticks of the UTC time, but with flags that look like a
local date.
*/
int64_t offset = 0;
int64_t ticks = (date_data & static_cast<int64_t>(OMNI_TICKS_MASK_FW));
// Negative ticks are stored in the top part of the range and should be converted back into a negative number
if (ticks > OMNI_TICKS_CEILING_FW - OMNI_TICKS_PER_DAY) {
ticks -= OMNI_TICKS_CEILING_FW;
}
// Convert the ticks back to local. If the UTC ticks are out of range, we need to default to
// the UTC offset from MinValue and MaxValue to be consistent with Parse.
if (ticks < 0) {
// offsetTicks = TimeZoneInfo.GetLocalUtcOffset(DateTime.MinValue, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks;
offset = (omni::chrono::span_t(0, 0, static_cast<omni::chrono::span_t::span_t>(omni::chrono::date_time::offset_from_utc()))).ticks();
} else if (ticks > OMNI_MAX_TICKS_FW) {
// offsetTicks = TimeZoneInfo.GetLocalUtcOffset(DateTime.MaxValue, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks;
offset = (omni::chrono::span_t(0, 0, (OMNI_MAX_TICKS_FW / OMNI_TICKS_PER_SECOND))).ticks();
} else {
// Because the ticks conversion between UTC and local is lossy, we need to capture whether the
// time is in a repeated hour so that it can be passed to the DateTime constructor.
offset = (omni::chrono::span_t(0, 0, static_cast<omni::chrono::span_t::span_t>(omni::chrono::date_time::offset_from_utc()))).ticks();
}
ticks += offset;
// Another behaviour of parsing is to cause small times to wrap around, so that they can be used
// to compare times of day
if (ticks < 0) {
ticks += OMNI_TICKS_PER_DAY;
}
if (ticks < 0 || ticks > OMNI_MAX_TICKS_FW) {
OMNI_ERR_RETV_FW("Invalid binary tick count specified", omni::exceptions::invalid_range("Invalid binary tick count specified"), omni::chrono::date_time())
}
return omni::chrono::date_time(static_cast<uint64_t>(ticks), omni::chrono::date_time_kind::LOCAL);
}
return omni::chrono::date_time::_from_binary_raw(date_data);
}
omni::chrono::date_time omni::chrono::date_time::from_file_time(int64_t file_time)
{
return omni::chrono::date_time::from_file_time_utc(file_time).to_local_time();
}
omni::chrono::date_time omni::chrono::date_time::from_file_time_utc(int64_t file_time)
{
if ((file_time < 0) || (file_time > (OMNI_MAX_TICKS_FW - OMNI_FILE_TIME_OFFSET))) {
OMNI_ERR_RETV_FW("Invalid file time specified", omni::exceptions::invalid_range("Invalid file time specified"), omni::chrono::date_time())
}
// This is the ticks in Universal time for this file_time.
int64_t uticks = file_time + OMNI_FILE_TIME_OFFSET;
return omni::chrono::date_time(static_cast<uint64_t>(uticks), omni::chrono::date_time_kind::UTC);
}
omni::chrono::date_time omni::chrono::date_time::from_oa_date(double oa_val)
{
return omni::chrono::date_time(static_cast<uint64_t>(omni::chrono::date_time::_double_date_to_ticks(oa_val)), omni::chrono::date_time_kind::UNSPECIFIED);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(const omni::chrono::date_time& other, const omni::chrono::span_t& offset)
{
omni::chrono::date_time obj(omni::chrono::date_time::specify_kind(other, omni::chrono::date_time_kind::LOCAL));
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(const omni::chrono::date_time& other, const omni::chrono::span_t& offset, const omni::chrono::date_time_kind& kind)
{
omni::chrono::date_time obj(omni::chrono::date_time::specify_kind(other, kind));
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(uint64_t ticks, const omni::chrono::span_t& offset)
{
omni::chrono::date_time obj(ticks, omni::chrono::date_time_kind::LOCAL);
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(uint64_t ticks, const omni::chrono::span_t& offset, const omni::chrono::date_time_kind& kind)
{
omni::chrono::date_time obj(ticks, kind);
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, const omni::chrono::span_t& offset)
{
omni::chrono::date_time obj(year, month, day, hour, minute, second, omni::chrono::date_time_kind::LOCAL);
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, const omni::chrono::span_t& offset, const omni::chrono::date_time_kind& kind)
{
omni::chrono::date_time obj(year, month, day, hour, minute, second, kind);
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, uint16_t millisecond, const omni::chrono::span_t& offset)
{
omni::chrono::date_time obj(year, month, day, hour, minute, second, millisecond, omni::chrono::date_time_kind::LOCAL);
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::chrono::date_time omni::chrono::date_time::from_offset(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, uint16_t millisecond, const omni::chrono::span_t& offset, const omni::chrono::date_time_kind& kind)
{
omni::chrono::date_time obj(year, month, day, hour, minute, second, millisecond, kind);
return omni_chrono_date_time_internal_offset(obj, offset);
}
omni::sequence::string_t omni::chrono::date_time::get_date_time_formats()
{
omni::sequence::string_t result;
// case 'd':
result.push_back(omni::string::to_string_t("MM/dd/yyyy"));
result.push_back(omni::string::to_string_t("yyyy-MM-dd"));
// case 'D':
result.push_back(omni::string::to_string_t("dddd, dd MMMM yyyy"));
// case 't':
result.push_back(omni::string::to_string_t("HH:mm"));
result.push_back(omni::string::to_string_t("hh:mm tt"));
result.push_back(omni::string::to_string_t("H:mm"));
result.push_back(omni::string::to_string_t("h:mm tt"));
// case 'T':
result.push_back(omni::string::to_string_t("HH:mm:ss"));
// case 'y': case 'Y':
result.push_back(omni::string::to_string_t("yyyy MMMM"));
// case 'f': case 'F':
result.push_back(omni::string::to_string_t("dddd, dd MMMM yyyy"));
result.push_back(omni::string::to_string_t("HH:mm"));
result.push_back(omni::string::to_string_t("hh:mm tt"));
result.push_back(omni::string::to_string_t("H:mm"));
result.push_back(omni::string::to_string_t("h:mm tt"));
// case 'U':
result.push_back(omni::string::to_string_t("dddd, dd MMMM yyyy"));
result.push_back(omni::string::to_string_t("HH:mm:ss"));
// case 'g':
result.push_back(omni::string::to_string_t("MM/dd/yyyy"));
result.push_back(omni::string::to_string_t("yyyy-MM-dd"));
result.push_back(omni::string::to_string_t("HH:mm"));
result.push_back(omni::string::to_string_t("hh:mm tt"));
result.push_back(omni::string::to_string_t("H:mm"));
result.push_back(omni::string::to_string_t("h:mm tt"));
// case 'G':
result.push_back(omni::string::to_string_t("MM/dd/yyyy"));
result.push_back(omni::string::to_string_t("yyyy-MM-dd"));
result.push_back(omni::string::to_string_t("HH:mm:ss"));
// case 'm': case 'M':
result.push_back(omni::string::to_string_t("MMMM dd"));
// case 'o': case 'O':
result.push_back(omni::string::to_string_t("yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK"));
// case 'r': case 'R':
result.push_back(omni::string::to_string_t("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"));
// case 's':
result.push_back(omni::string::to_string_t("yyyy'-'MM'-'dd'T'HH':'mm':'ss"));
// case 'u':
result.push_back(omni::string::to_string_t("yyyy'-'MM'-'dd HH':'mm':'ss'Z'"));
return result;
}
omni::sequence::string_t omni::chrono::date_time::get_date_time_formats(char format)
{
omni::sequence::string_t result;
switch (format)
{
case 'd':
result.push_back(omni::string::to_string_t("MM/dd/yyyy"));
result.push_back(omni::string::to_string_t("yyyy-MM-dd"));
break;
case 'D':
result.push_back(omni::string::to_string_t("dddd, dd MMMM yyyy"));
break;
case 't':
result.push_back(omni::string::to_string_t("HH:mm"));
result.push_back(omni::string::to_string_t("hh:mm tt"));
result.push_back(omni::string::to_string_t("H:mm"));
result.push_back(omni::string::to_string_t("h:mm tt"));
break;
case 'T':
result.push_back(omni::string::to_string_t("HH:mm:ss"));
break;
case 'y': case 'Y':
result.push_back(omni::string::to_string_t("yyyy MMMM"));
break;
case 'f': case 'F':
result.push_back(omni::string::to_string_t("dddd, dd MMMM yyyy"));
result.push_back(omni::string::to_string_t("HH:mm"));
result.push_back(omni::string::to_string_t("hh:mm tt"));
result.push_back(omni::string::to_string_t("H:mm"));
result.push_back(omni::string::to_string_t("h:mm tt"));
break;
case 'U':
result.push_back(omni::string::to_string_t("dddd, dd MMMM yyyy"));
result.push_back(omni::string::to_string_t("HH:mm:ss"));
break;
case 'g':
result.push_back(omni::string::to_string_t("MM/dd/yyyy"));
result.push_back(omni::string::to_string_t("yyyy-MM-dd"));
result.push_back(omni::string::to_string_t("HH:mm"));
result.push_back(omni::string::to_string_t("hh:mm tt"));
result.push_back(omni::string::to_string_t("H:mm"));
result.push_back(omni::string::to_string_t("h:mm tt"));
break;
case 'G':
result.push_back(omni::string::to_string_t("MM/dd/yyyy"));
result.push_back(omni::string::to_string_t("yyyy-MM-dd"));
result.push_back(omni::string::to_string_t("HH:mm:ss"));
break;
case 'm': case 'M':
result.push_back(omni::string::to_string_t("MMMM dd"));
break;
case 'o': case 'O':
result.push_back(omni::string::to_string_t("yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK"));
break;
case 'r': case 'R':
result.push_back(omni::string::to_string_t("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"));
break;
case 's':
result.push_back(omni::string::to_string_t("yyyy'-'MM'-'dd'T'HH':'mm':'ss"));
break;
case 'u':
result.push_back(omni::string::to_string_t("yyyy'-'MM'-'dd HH':'mm':'ss'Z'"));
break;
default:
OMNI_ERR_RETV_FW("Invalid format specified", omni::exceptions::invalid_string_format(), omni::sequence::string_t())
}
return result;
}
double omni::chrono::date_time::offset_from_utc()
{
double offset_seconds = 0;
omni_date_time_internal_offset_from_utc(&offset_seconds);
return offset_seconds;
}
omni::chrono::date_time omni::chrono::date_time::specify_kind(const omni::chrono::date_time& value, const omni::chrono::date_time_kind& kind)
{
return omni::chrono::date_time(static_cast<uint64_t>(value._ticks()), kind);
}
omni::chrono::date_time omni::chrono::date_time::now()
{
double offset_seconds = 0;
bool dst = omni_date_time_internal_offset_from_utc(&offset_seconds);
omni::chrono::date_time obj((omni_date_time_internal_get_ticks() | (dst ? OMNI_DATE_KIND_LOCAL_DST_FW : OMNI_DATE_KIND_LOCAL_FW)), "");
return omni_chrono_date_time_internal_offset(obj, omni::chrono::span_t(0, 0, static_cast<omni::chrono::span_t::span_t>(offset_seconds)));
}
omni::chrono::date_time omni::chrono::date_time::utc_now()
{
return omni::chrono::date_time((omni_date_time_internal_get_ticks() | OMNI_DATE_KIND_UTC_FW), "");
}
omni::chrono::date_time omni::chrono::date_time::today()
{
return omni::chrono::date_time::now().date();
}
bool omni::chrono::date_time::is_leap_year(uint16_t year)
{
if ((year < 1) || (year > OMNI_DATE_MAX_YEAR)) {
OMNI_ERR_RETV_FW("Invalid year specified", omni::exceptions::invalid_range("Invalid year specified"), false)
}
return omni_date_time_internal_is_leap_year(year);
}
bool omni::chrono::date_time::is_leap_year(const omni::chrono::date_time& date)
{
return omni::chrono::date_time::is_leap_year(date.year());
}
bool omni::chrono::date_time::is_leap_day(uint16_t year, uint16_t month, uint16_t day)
{
if (omni::chrono::date_time::is_leap_year(year)) {
if ((month < 1) || (month > 12)) {
OMNI_ERR_RETV_FW("Invalid month specified", omni::exceptions::invalid_range("Invalid month specified"), false)
}
if ((day < 1) || (day > 32)) {
OMNI_ERR_RETV_FW("Invalid day specified", omni::exceptions::invalid_range("Invalid day specified"), false)
}
if (omni_date_time_internal_check_day_range(year, month, day)) {
OMNI_ERR_RETV_FW("Invalid day specified for the year and month", omni::exceptions::invalid_range("Invalid day specified for the year and month"), false)
}
return ((month == 2) && (day == 29));
}
return false;
}
bool omni::chrono::date_time::is_leap_day(const omni::chrono::date_time& date)
{
return omni::chrono::date_time::is_leap_day(date.year(), date.month(), date.day());
}
bool omni::chrono::date_time::is_valid_day(uint16_t year, uint16_t month, uint16_t day)
{
return omni_date_time_internal_check_day_range(year, month, day);
}
uint16_t omni::chrono::date_time::to_four_digit_year(uint16_t year, uint16_t two_digit_year_max)
{
if ((year < 1) || (year > OMNI_DATE_MAX_YEAR)) {
OMNI_ERR_RETV_FW("Invalid year specified", omni::exceptions::invalid_range("Invalid year specified"), false)
}
if (year >= 100) {
// if it's 100 or higher, no need to do the 2 digit year comparison
return year;
}
return static_cast<uint16_t>((((two_digit_year_max / 100) - ((year > (two_digit_year_max % 100)) ? 1 : 0)) * 100) + year);
}
uint16_t omni::chrono::date_time::to_four_digit_year(uint16_t year)
{
return omni::chrono::date_time::to_four_digit_year(year, omni::chrono::date_time::now().year() + OMNI_DATE_TWO_DIGIT_YEAR_MAX);
}
bool omni::chrono::date_time::try_create(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, uint16_t millisecond, omni::chrono::date_time& result)
{
return omni::chrono::date_time::_try_create(year, month, day, hour, minute, second, millisecond, result);
}
omni::chrono::date_time omni::chrono::date_time::parse(const std::string& date_string)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::parse(date_string, current_info, omni::chrono::date_time_styles::NONE);
}
bool omni::chrono::date_time::try_parse(const std::string& date_string, omni::chrono::date_time& result)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::try_parse(date_string, current_info, omni::chrono::date_time_styles::NONE, result);
}
bool omni::chrono::date_time::try_parse(const std::string& date_string, omni::chrono::date_time& result, omni::chrono::date_time_parse_failure& fail_reason)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::try_parse(date_string, current_info, omni::chrono::date_time_styles::NONE, result, fail_reason);
}
omni::chrono::date_time omni::chrono::date_time::parse_exact(const std::string& date_string, const std::string& format)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::date_time_parse::parse_exact(date_string, format, current_info, omni::chrono::date_time_styles::NONE);
}
omni::chrono::date_time omni::chrono::date_time::parse_exact(const std::string& date_string, const std::string& format, const omni::chrono::date_time_styles& style)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::date_time_parse::parse_exact(date_string, format, current_info, style);
}
bool omni::chrono::date_time::try_parse_exact(const std::string& date_string, const std::string& format, omni::chrono::date_time& result)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::date_time_parse::try_parse_exact(date_string, format, current_info, omni::chrono::date_time_styles::NONE, result);
}
bool omni::chrono::date_time::try_parse_exact(const std::string& date_string, const std::string& format, const omni::chrono::date_time_styles& style, omni::chrono::date_time& result)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::date_time_parse::try_parse_exact(date_string, format, current_info, style, result);
}
bool omni::chrono::date_time::try_parse_exact(const std::string& date_string, const std::string& format, omni::chrono::date_time& result, omni::chrono::date_time_parse_failure& fail_reason)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::date_time_parse::try_parse_exact(date_string, format, current_info, omni::chrono::date_time_styles::NONE, result, fail_reason);
}
bool omni::chrono::date_time::try_parse_exact(const std::string& date_string, const std::string& format, const omni::chrono::date_time_styles& style, omni::chrono::date_time& result, omni::chrono::date_time_parse_failure& fail_reason)
{
omni::internal::date_time_format::format_info current_info;
return omni::internal::date_time_format::date_time_parse::try_parse_exact(date_string, format, current_info, style, result, fail_reason);
}
// -- start private static methods --
int64_t omni::chrono::date_time::_date_to_ticks(uint16_t year, uint16_t month, uint16_t day)
{
if ((year >= 1) && (year <= OMNI_DATE_MAX_YEAR) && (month >= 1) && (month <= 12)) {
#if defined(OMNI_NO_CONSTS)
const int32_t d365[] = OMNI_DAYS_TO_MONTH_365;
const int32_t d366[] = OMNI_DAYS_TO_MONTH_366;
const int32_t* days = omni::chrono::is_leap_year(year) ? &d366[0]: &d365[0];
#else
const int32_t* days = omni::chrono::is_leap_year(year) ?
&omni::chrono::DAYS_TO_MONTH_366[0]:
&omni::chrono::DAYS_TO_MONTH_365[0];
#endif
if ((day >= 1) && (day <= (days[month] - days[month - 1]))) {
int32_t y = year - 1;
return ((y * 365) + (y / 4) - (y / 100) + (y / 400) + days[month - 1] + day - 1) * OMNI_TICKS_PER_DAY;
}
}
OMNI_ERR_RETV_FW("Invalid year/month/day specified", omni::exceptions::invalid_range("Invalid year/month/day specified"), 0)
}
int64_t omni::chrono::date_time::_time_to_ticks(uint16_t hour, uint16_t minute, uint16_t second)
{
//omni::chrono::time_span.TimeToTicks is a family access function which does no error checking, so
//we need to put some error checking out here.
if ((hour < 24) && (minute < 60) && (second < 60)) {
return omni::chrono::time_span::from_time(hour, minute, second).ticks();
}
OMNI_ERR_RETV_FW("Invalid hour/minute/second specified", omni::exceptions::invalid_range("Invalid hour/minute/second specified"), 0)
}
int64_t omni::chrono::date_time::_double_date_to_ticks(double value)
{
// DEV_NOTE: the comments are from the .NET source .. thanks to you whomever you were
// The check done this way will take care of NaN
if (!(value < OMNI_OA_DATE_MAX_AS_DOUBLE) || !(value > OMNI_OA_DATE_MIN_AS_DOUBLE)) {
OMNI_ERR_RETV_FW("Invalid OLE date specified", omni::exceptions::invalid_range("Invalid OLE date specified"), 0)
}
// Conversion to long will not cause an overflow here, as at this point the "value" is in between OADateMinAsDouble and OADateMaxAsDouble
int64_t millis = static_cast<int64_t>(value * OMNI_MILLISECONDS_PER_DAY + (value >= 0? 0.5: -0.5));
// The interesting thing here is when you have a value like 12.5 it all positive 12 days and 12 hours from 01/01/1899
// However if you a value of -12.25 it is minus 12 days but still positive 6 hours, almost as though you meant -11.75 all negative
// This line below fixes up the millis in the negative case
if (millis < 0) {
millis -= (millis % OMNI_MILLISECONDS_PER_DAY) * 2;
}
millis += OMNI_DOUBLE_DATE_OFFSET / OMNI_TICKS_PER_MILLISECOND;
if (millis < 0 || millis >= OMNI_MAX_MILLIS_FW) {
OMNI_ERR_RETV_FW("Invalid OLE milliseconds specified", omni::exceptions::invalid_range(), 0)
}
return millis * OMNI_TICKS_PER_MILLISECOND;
}
omni::chrono::date_time omni::chrono::date_time::_from_binary_raw(int64_t date_data)
{
int64_t ticks = (date_data & static_cast<int64_t>(OMNI_TICKS_MASK_FW));
if ((ticks < 0) || (ticks > OMNI_MAX_TICKS_FW)) {
OMNI_ERR_RETV_FW("Invalid binary tick value", omni::exceptions::invalid_range("Invalid binary tick value"), omni::chrono::date_time())
}
return omni::chrono::date_time(static_cast<uint64_t>(date_data));
}
double omni::chrono::date_time::_ticks_to_oa_date(int64_t value)
{
// DEV_NOTE: the notes are from the .NET source code
if (value == 0) {
return 0.0; // Returns OleAut's zero'ed date value.
}
if (value < OMNI_TICKS_PER_DAY) { // This is a fix for VB. They want the default day to be 1/1/0001 rather then 12/30/1899.
value += OMNI_DOUBLE_DATE_OFFSET; // We could have moved this fix down but we would like to keep the bounds check.
}
if (value < OMNI_OA_DATE_MIN_AS_TICKS) {
OMNI_ERR_RETV_FW("Invalid OLE date specified", omni::exceptions::invalid_range("Invalid OLE date specified), 0)
}
// Currently, our max date == OA's max date (12/31/9999), so we don't
// need an overflow check in that direction.
int64_t ms = (value - OMNI_DOUBLE_DATE_OFFSET) / OMNI_TICKS_PER_MILLISECOND;
if (ms < 0) {
int64_t frac = ms % OMNI_MILLISECONDS_PER_DAY;
if (frac != 0) {
ms -= (OMNI_MILLISECONDS_PER_DAY + frac) * 2;
}
}
return static_cast<double>(ms) / OMNI_MILLISECONDS_PER_DAY;
}
bool omni::chrono::date_time::_try_create(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second, uint16_t millisecond, omni::chrono::date_time& result)
{
result = omni::chrono::date_time::min_value();
if (year < 1 || year > OMNI_DATE_MAX_YEAR || month < 1 || month > 12) {
return false;
}
if (omni::chrono::date_time::is_leap_year(year)) {
#if defined(OMNI_NO_CONSTS)
const int32_t d366[] = OMNI_DAYS_TO_MONTH_366;
if (day < 1 || day > d366[month] - d366[month - 1]) {
return false;
}
#else
if (day < 1 || day > omni::chrono::DAYS_TO_MONTH_366[month] - omni::chrono::DAYS_TO_MONTH_366[month - 1]) {
return false;
}
#endif
} else {
#if defined(OMNI_NO_CONSTS)
const int32_t d365[] = OMNI_DAYS_TO_MONTH_365;
if (day < 1 || day > d365[month] - d365[month - 1]) {
return false;
}
#else
if (day < 1 || day > omni::chrono::DAYS_TO_MONTH_365[month] - omni::chrono::DAYS_TO_MONTH_365[month - 1]) {
return false;
}
#endif
}
if (hour >= 24 || minute >= 60 || second >= 60) {
return false;
}
if (millisecond >= OMNI_MILLISECONDS_PER_SECOND) {
return false;
}
int64_t ticks = omni::chrono::date_time::_date_to_ticks(year, month, day) + omni::chrono::date_time::_time_to_ticks(hour, minute, second);
ticks += millisecond * OMNI_TICKS_PER_MILLISECOND;
if (ticks < 0 || ticks > OMNI_MAX_TICKS_FW) {
return false;
}
result = omni::chrono::date_time(static_cast<uint64_t>(ticks), omni::chrono::date_time_kind::UNSPECIFIED);
return true;
}