Skip to content

Instantly share code, notes, and snippets.

@HowardHinnant
Created June 25, 2016 02:24
Show Gist options
  • Save HowardHinnant/38cc4b5d5438736f4b75795b879f99f3 to your computer and use it in GitHub Desktop.
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.
// 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