Skip to content

A lightweight C++17 header-only library for parsing and formatting human-readable time durations (e.g., "2d 5h 30m"). Supports chrono integration, SQL interval output, and flexible duration construction.

License

Notifications You must be signed in to change notification settings

Anime-pdf/timeduration-cpp

Repository files navigation

timeduration-cpp

A modern C++17 header-only library for parsing and manipulating human-readable time durations.

Build and Test

Features

  • Header-only: Easy integration into any C++ project
  • Modern C++17: Uses standard library chrono types
  • Flexible parsing: Supports multiple time formats and units
  • Type-safe: Built on std::chrono::seconds for accuracy
  • Zero dependencies: No external libraries required for the core functionality
  • Cross-platform: Works on Windows, Linux, and macOS
  • SQL integration: Generate SQL-compatible interval strings

Quick Start

#include <timeduration/timeduration.hpp> #include <iostream> int main() { using namespace timeduration; // Parse a time duration string CTimePeriod duration("2h 30m 15s"); // Access individual components std::cout << "Hours: " << duration.hours() << std::endl; // 2 std::cout << "Minutes: " << duration.minutes() << std::endl; // 30 std::cout << "Seconds: " << duration.seconds() << std::endl; // 15 // Get total duration in seconds std::cout << "Total: " << duration.duration().count() << " seconds" << std::endl; // 9015 // Format back to string std::cout << "Formatted: " << duration.toString() << std::endl; // "2h 30m 15s" return 0; }

Installation

Using CMake (Recommended)

  1. Clone the repository:

    git clone https://github.com/anime-pdf/timeduration-cpp.git cd timeduration-cpp
  2. Build and install:

    mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release cmake --build . sudo cmake --install .
  3. Use in your CMake project:

    find_package(timeduration REQUIRED) target_link_libraries(your_target PRIVATE timeduration::timeduration)

Header-only Integration

Simply copy include/timeduration/timeduration.hpp to your project and include it:

#include "timeduration.hpp"

Supported Time Units

The library supports both short and long forms of time units:

Unit Short Form Long Form Seconds
Seconds s seconds 1
Minutes m minutes 60
Hours h hours 3,600
Days d days 86,400
Months mo months 2,419,200 (28 days)
Years y years 31,536,000 (365 days)

Usage Examples

Basic Parsing

using namespace timeduration; // Different formats CTimePeriod p1("5s"); // 5 seconds CTimePeriod p2("10m"); // 10 minutes  CTimePeriod p3("2h"); // 2 hours CTimePeriod p4("1d"); // 1 day // Combined formats CTimePeriod p5("1h 30m"); // 1 hour 30 minutes CTimePeriod p6("2d 5h 30m 15s"); // 2 days 5 hours 30 minutes 15 seconds // Long form CTimePeriod p7("1hours 30minutes 45seconds"); // Large units CTimePeriod p8("1y 6mo 15d"); // 1 year 6 months 15 days

Construction Methods

// From string CTimePeriod duration1("2h 30m"); // From components (seconds, minutes, hours, days) CTimePeriod duration2(15, 30, 2, 1); // 1d 2h 30m 15s // From std::chrono::seconds CTimePeriod duration3(std::chrono::seconds(3661)); // 1h 1m 1s // Using factory method auto duration4 = CTimePeriod::ParseFactory("5h 15m"); // Default constructor (zero duration) CTimePeriod duration5; // 0s

Accessing Components

CTimePeriod duration("1d 5h 30m 45s"); std::cout << "Days: " << duration.days() << std::endl; // 1 std::cout << "Hours: " << duration.hours() << std::endl; // 5 std::cout << "Minutes: " << duration.minutes() << std::endl; // 30 std::cout << "Seconds: " << duration.seconds() << std::endl; // 45 // Total duration as std::chrono::seconds auto total = duration.duration(); std::cout << "Total seconds: " << total.count() << std::endl; // 106245 // Check if zero if (duration.isZero()) { std::cout << "Duration is zero" << std::endl; }

Formatting and Output

CTimePeriod duration("2h 30m 15s"); // Human-readable string std::cout << duration.toString() << std::endl; // "2h 30m 15s" // SQL interval format std::cout << duration.asSqlInterval() << std::endl; // "interval 9015 second"

Comparisons

CTimePeriod short_duration("30m"); CTimePeriod long_duration("1h"); // Equality if (short_duration == long_duration) { /* ... */ } if (short_duration != long_duration) { /* ... */ } // Relational if (short_duration < long_duration) { /* true */ } if (short_duration > long_duration) { /* false */ } if (short_duration <= long_duration) { /* true */ } if (short_duration >= long_duration) { /* false */ }

Advanced Usage

// Handle normalization automatically CTimePeriod duration(75); // 75 seconds becomes 1m 15s std::cout << duration.toString() << std::endl; // "1m 15s" // Accumulating durations CTimePeriod total; std::vector<std::string> durations = {"1h", "30m", "45s"}; for (const auto& d : durations) { CTimePeriod current(d); total = CTimePeriod(total.duration() + current.duration()); } std::cout << total.toString() << std::endl; // "1h 30m 45s" // Parse large numbers CTimePeriod huge("999h 123456s"); std::cout << huge.toString() << std::endl; // Normalized output

Parser Architecture

Scanner (Tokenizer)

The CScanner class handles the low-level tokenization of input strings:

  • Token Recognition: Identifies numbers and unit suffixes
  • Flexible Parsing: Handles both "5m" and "5 minutes" formats
  • Accumulation: Combines multiple instances of the same unit (e.g., "5m 10m" = "15m")
  • Default Units: Numbers without units default to minutes

Scanner Behavior

// Internal scanner usage (normally automatic) CTimePeriod::TokenHolder tokens = { {"s", 1L}, {"seconds", 1L}, {"m", 60L}, {"minutes", 60L}, {"h", 3600L}, {"hours", 3600L}, // ... more units }; CTimePeriod::CScanner scanner("2h 30m 15s", tokens); auto result = scanner.ScanTokens(); // result contains: {3600: 2, 60: 30, 1: 15}

Parser (Duration Calculator)

The parser converts scanner results into std::chrono::seconds:

  • Multiplier Application: Applies time unit multipliers to values
  • Accumulation: Sums all components into total seconds
  • Normalization: Breaks down total seconds into days, hours, minutes, seconds

Parse Process

  1. Input: "2h 30m 15s"
  2. Tokenization: {3600: 2, 60: 30, 1: 15}
  3. Calculation: 2×3600 + 30×60 + 15×1 = 9015 seconds
  4. Normalization: 9015s → 0d 2h 30m 15s

Building from Source

Prerequisites

  • C++17 compatible compiler
  • CMake 3.14 or later
  • Git

Build Options

# Configure with options cmake -B build \ -DCMAKE_BUILD_TYPE=Release \ -DTIMEDURATION_BUILD_TESTS=ON \ -DTIMEDURATION_BUILD_EXAMPLES=ON # Build cmake --build build --config Release # Run tests cd build && ctest --output-on-failure # Install cmake --install build --prefix /usr/local

CMake Options

Option Default Description
TIMEDURATION_BUILD_TESTS OFF Build unit tests
TIMEDURATION_BUILD_EXAMPLES OFF Build example programs
TIMEDURATION_DOWNLOAD_GTEST ON Auto-download Google Test if not found

Testing

The library includes comprehensive unit tests covering:

  • Scanner functionality: Tokenization and parsing logic
  • Parser accuracy: Duration calculation and normalization
  • Edge cases: Zero durations, large numbers, malformed input
  • API completeness: All public methods and operators
  • Integration: Round-trip conversions and complex scenarios

Run tests with:

# Build with tests enabled cmake -B build -DTIMEDURATION_BUILD_TESTS=ON cmake --build build # Run all tests cd build && ctest --output-on-failure # Run specific test patterns cd build && ctest -R "Scanner" --verbose

Performance Considerations

  • Header-only: No runtime linking overhead
  • Parse caching: Consider caching parsed durations for repeated use
  • Memory efficient: Uses standard integers and chrono types
  • Stack allocated: No dynamic memory allocation during normal operation

Error Handling

The library follows a simple error handling strategy:

  • Malformed input: Returns zero duration
  • Unknown units: Ignored during parsing
  • Overflow: Undefined behavior for extremely large values (same as standard integers)
// These all result in zero or partial parsing CTimePeriod invalid1(""); // Empty string → 0s CTimePeriod invalid2("invalid"); // No numbers → 0s CTimePeriod partial("5h invalid"); // Partial parse → 5h 0m 0s

Integration Examples

With std::chrono

#include <chrono> #include <thread> CTimePeriod delay("5s"); std::this_thread::sleep_for(delay.duration());

With Database Queries

CTimePeriod retention("30d"); std::string query = "DELETE FROM logs WHERE created_at < NOW() - " + retention.asSqlInterval();

Configuration Files

#include <fstream> #include <sstream> std::ifstream config("config.txt"); std::string line; while (std::getline(config, line)) { if (line.starts_with("timeout=")) { std::string duration_str = line.substr(8); CTimePeriod timeout(duration_str); // Use timeout.duration() for network operations } }

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Make your changes and add tests
  4. Ensure all tests pass: cmake --build build && cd build && ctest
  5. Submit a pull request

Code Style

  • Follow the existing code style
  • Use meaningful variable names
  • Add unit tests for new functionality
  • Update documentation for API changes

License

MIT License - see LICENSE file for details.

Changelog

FAQ

Q: Why use this instead of std::chrono parsing? A: std::chrono doesn't provide built-in parsing for human-readable formats like "2h 30m". This library bridges that gap.

Q: Are months and years exact? A: For simplicity, months are 28 days and years are 365 days. For precise calendar arithmetic, use a dedicated date/time library.

Q: Can I extend the supported units? A: Currently, units are hardcoded. Future versions may support custom unit definitions.

Q: What about negative durations? A: Negative durations are not currently supported. All parsed values are treated as positive.

Q: Is it thread-safe? A: Yes, the library is thread-safe for read operations. Multiple threads can safely parse durations simultaneously.

About

A lightweight C++17 header-only library for parsing and formatting human-readable time durations (e.g., "2d 5h 30m"). Supports chrono integration, SQL interval output, and flexible duration construction.

Topics

Resources

License

Stars

Watchers

Forks