Created
June 25, 2016 02:24
-
-
Save HowardHinnant/38cc4b5d5438736f4b75795b879f99f3 to your computer and use it in GitHub Desktop.
Example: Application to convert seconds from 2000-01-01 UTC to and from local America/Los_Angeles time.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// clang++ -std=c++14 rippled_conversion.cpp -o rippled_conversion -I../date ../date/tz.cpp -O3 -lcurl | |
#include "tz.h" // Requires: http://howardhinnant.github.io/date/tz.html | |
#include <chrono> | |
#include <iostream> | |
#include <sstream> | |
#include <stdexcept> | |
#include <string> | |
#include <thread> | |
// place is the only configuration required for geography | |
constexpr auto place = "America/Los_Angeles"; | |
// The alternate epoch: | |
using namespace date::literals; | |
constexpr date::sys_days epoch = jan/1/2000; | |
// Local using namespace directives avoided only for educational purposes, | |
// except for std::chrono_literals, and date::literals. (this program is a tutorial) | |
// Helper for parse_date | |
date::zoned_seconds | |
resolve_ambiguity(date::local_seconds local) | |
{ | |
std::cout << '\n' << local | |
<< " is ambiguous as it occurs twice on this date:\n"; | |
auto zone = date::locate_zone(place); | |
auto info = zone->get_info(local); | |
std::cout << "Once for " << info.first.abbrev | |
<< ", and then again for " << info.second.abbrev << ".\n" | |
"Please enter " << info.first.abbrev << " or " << info.second.abbrev | |
<< " to indicate the desired time: "; | |
std::string tz; | |
std::cin >> tz; | |
if (tz == info.first.abbrev) | |
return {zone, local, date::choose::earliest}; | |
if (tz == info.second.abbrev) | |
return {zone, local, date::choose::latest}; | |
std::ostringstream os; | |
os << tz << " is not a valid timezone\n\n"; | |
throw std::invalid_argument(os.str()); | |
} | |
date::zoned_seconds | |
parse_date() | |
{ | |
std::cin.ignore(); | |
std::cout << "Enter yyyy-mm-dd 00:00:00am/pm : "; | |
date::local_seconds ls; | |
date::parse(std::cin, "%F %I:%M:%S%p", ls); | |
if (std::cin.fail()) | |
throw std::runtime_error("\nI did not undertand that format\n\n"); | |
try | |
{ | |
return {place, ls}; | |
} | |
catch (date::ambiguous_local_time const&) | |
{ | |
} | |
return resolve_ambiguity(ls); | |
} | |
std::chrono::seconds | |
parse_seconds() | |
{ | |
std::cin.ignore(); | |
std::cout << "Enter rippled timestamp : "; | |
long ts; | |
std::cin >> ts; | |
if (std::cin.fail()) | |
{ | |
std::cin.clear(); | |
throw std::runtime_error("\nI didn't get that, please try again\n\n"); | |
} | |
return std::chrono::seconds{ts}; | |
} | |
void | |
convert_date_to_rippled() | |
{ | |
try | |
{ | |
auto zt = parse_date(); | |
auto ts = zt.get_sys_time() - epoch; | |
std::cout << date::format("\n%F %r %Z is ", zt) << ts.count() << "\n\n"; | |
} | |
catch (std::exception const& e) | |
{ | |
std::cin.clear(); | |
std::cerr << e.what() << '\n'; | |
} | |
} | |
void | |
convert_rippled_to_date() | |
{ | |
try | |
{ | |
auto ts = parse_seconds(); | |
auto zt = date::make_zoned(place, epoch + ts); | |
std::cout << "\n" << ts.count() << date::format(" is %F %r %Z\n\n", zt); | |
} | |
catch (std::exception const& e) | |
{ | |
std::cin.clear(); | |
std::cerr << e.what() << '\n'; | |
} | |
} | |
int | |
main() | |
{ | |
// Optimize by initializing tzdb (concurrently) while the user is typing | |
std::thread{date::get_tzdb}.detach(); | |
while (true) | |
{ | |
std::cout << "1. yyyy-mm-dd 00:00:00 " << place << " to rippled timestamp\n"; | |
std::cout << "2. rippled timestamp to yyyy-mm-dd 00:00:00 " << place << "\n"; | |
std::cout << "3. Display tzdata version\n"; | |
std::cout << "4. Exit\n"; | |
int choice; | |
std::cin >> choice; | |
if (std::cin.fail()) | |
{ | |
std::cout << "\nPlease enter 1, 2, 3 or 4.\n\n"; | |
std::cin.clear(); | |
std::string garbage; | |
std::getline(std::cin, garbage); | |
continue; | |
} | |
switch (choice) | |
{ | |
case 1: | |
convert_date_to_rippled(); | |
break; | |
case 2: | |
convert_rippled_to_date(); | |
break; | |
case 3: | |
std::cout << "\ntz database version = " << date::get_tzdb().version << "\n\n"; | |
break; | |
case 4: | |
std::cout << "Exiting.\n"; | |
return 0; | |
default: | |
std::cout << "\nPlease enter 1, 2, 3 or 4.\n\n"; | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment