comptime

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2024 License: MIT Imports: 4 Imported by: 1

README

Parse composite time durations, including support for days

The comptime package (composite time) offers functionality for parsing durations, extending the capabilities of the standard library's time.ParseDuration function. It introduces support for an additional time unit, 'days' (denoted by 'd'), and enables the parsing of composite durations from a single string, such as '1d5m200ms'.

Key Features:

  • Supports the following time units: "d" (days), "h" (hours), "m" (minutes), "s" (seconds), "ms" (milliseconds), and "us" (microseconds).
  • Capable of parsing composite durations such as "24d20h31m23s647ms".
  • Ensures parsed durations are non-negative.
  • Custom Range Checking: Allows the caller to define their own range constraints on parsed durations through a BoundsChecker callback. This enables early termination of the parsing process based on user-defined limits.

Dev Build

$ make
$ make benchmark
$ make benchmark-profile

Documentation

Overview

Package comptime (composite time) offers functionality for parsing durations, extending the capabilities of the standard library's `time.ParseDuration` function. It introduces support for an additional time unit, 'days' (denoted by 'd'), and enables the parsing of composite durations from a single string, such as '1d5m200ms'.

Key Features:

  • Supports the following time units: "d" (days), "h" (hours), "m" (minutes), "s" (seconds), "ms" (milliseconds), and "us" (microseconds).

  • Capable of parsing composite durations such as "24d20h31m23s647ms".

  • Ensures parsed durations are non-negative.

  • Custom Range Checking: Allows the user to define their own range constraints on parsed durations through a BoundsChecker callback. This enables early termination of the parsing process based on user-defined limits.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NoRangeChecking

func NoRangeChecking(position int, value time.Duration, totalSoFar time.Duration) bool

NoRangeChecking is a sentinel BoundsChecker function that allows the ParseDuration function to proceed without any range checks. This function always returns true, allowing the parsing to continue.

func ParseDuration

func ParseDuration(input string, defaultUnit Unit, parseMode ParseMode, inRangeChecker RangeChecker) (time.Duration, error)

ParseDuration translates an input string representing a time duration into a time.Duration type. The string may include values with the following units: "d" (days), "h" (hours), "m" (minutes), "s" (seconds), "ms" (milliseconds), "us" (microseconds).

Input examples:

  • 10s
  • 1h30m
  • 500ms
  • 100us
  • 1d5m200
  • 1000

The last two examples both contain values (e.g., 200 and 1000) that lack a unit specifier. These values will be interpreted according to the default unit provided as an argument to the ParseDuration function.

An empty input results in a zero duration.

Returns a time.Duration representing the parsed duration value from the input string. If the input is invalid or cannot be parsed into a valid time.Duration, the function will return one of the following error types:

  • SyntaxError: When the input has non-numeric values, unrecognised units, improperly formatted values, or units that are not in descending order from day to microsecond.

  • OverflowError: If the total duration exceeds the maximum limit that can be represented as a time.Duration, or if any individual value in the input leads to an overflow in the total duration. Takes precedence over RangeError.

  • RangeError: If the parsing is halted by a BoundsChecker callback returning false.

Note: If both OverflowError and RangeError conditions are met, OverflowError will take precedence.

Example

ExampleParseDuration gets copied to the documentation.

package main

import (
	"fmt"
	"os"

	"github.com/frobware/comptime"
)

func main() {
	if duration, err := comptime.ParseDuration("1h", comptime.Millisecond, comptime.ParseModeSingleUnit, comptime.NoRangeChecking); err != nil {
		fmt.Fprintln(os.Stderr, err)
	} else {
		fmt.Printf("%vms\n", duration.Milliseconds())
	}

	if duration, err := comptime.ParseDuration("24d20h31m23s647ms", comptime.Millisecond, comptime.ParseModeMultiUnit, comptime.NoRangeChecking); err != nil {
		fmt.Fprintln(os.Stderr, err)
	} else {
		fmt.Printf("%vms\n", duration.Milliseconds())
	}

	if duration, err := comptime.ParseDuration("500", comptime.Millisecond, comptime.ParseModeMultiUnit, comptime.NoRangeChecking); err != nil {
		fmt.Fprintln(os.Stderr, err)
	} else {
		fmt.Printf("%vms\n", duration.Milliseconds())
	}

}
Output:

3600000ms
2147483647ms
500ms

Types

type OverflowError

type OverflowError struct {
	// contains filtered or unexported fields
}

OverflowError represents an error that occurs when a parsed value exceeds the allowable range, leading to an overflow condition.

func (*OverflowError) Error

func (e *OverflowError) Error() string

Error returns a formatted message indicating the position and value that caused the overflow, and includes additional context from any underlying error, if present. The position in the error message is converted to 1-based indexing, rather than the original 0-based indexing used in the input string. 1-indexed.

func (*OverflowError) Is

func (e *OverflowError) Is(target error) bool

Is checks whether the provided target error matches the OverflowError type. This method facilitates the use of the errors.Is function for matching against OverflowError.

Example:

if errors.Is(err, &comptime.OverflowError{}) {
    // handle OverflowError
}

func (*OverflowError) Position

func (e *OverflowError) Position() int

Position returns the position in the input string where the OverflowError occurred. The position is 0-based, indicating that the first character in the input string is at position 0.

type ParseMode

type ParseMode int

ParseMode defines the behavior for interpreting units in a duration string. It decides how many units can be accepted when parsing.

const (
	// ParseModeMultiUnit allows for multiple units to be
	// specified together in the duration string, e.g., "1d2h3m".
	ParseModeMultiUnit ParseMode = iota

	// ParseModeSingleUnit permits only a single unit type to be
	// present in the duration string. Any subsequent unit types
	// will result in an error. For instance, "1d" would be valid,
	// but "1d2h" would not.
	ParseModeSingleUnit
)

type RangeChecker

type RangeChecker func(position int, value time.Duration, totalSoFar time.Duration) bool

RangeChecker is a function type that serves as a callback during the parsing process in ParseDuration. The callback is invoked every time a new composite duration (unit * value) is calculated.

Parameters:

  • position: The current position in the input string where the composite duration was parsed.

  • value: The composite duration that was just calculated (unit * value).

  • totalSoFar: The total duration that has been parsed so far.

The callback returns a boolean that determines whether parsing should continue (true) or stop immediately (false). If the parsing is halted, a RangeError will be returned from the ParseDuration function.

type RangeError

type RangeError struct {
	// contains filtered or unexported fields
}

RangeError represents a condition where a parsed value exceeds a user-defined allowable range.

func (*RangeError) Error

func (e *RangeError) Error() string

Error returns a formatted message indicating the position where the allowable range was exceeded. The position in the error message is converted to 1-based indexing, rather than the original 0-based indexing used in the input string.

func (*RangeError) Is

func (e *RangeError) Is(target error) bool

Is checks whether the provided target error matches the RangeError type. This method facilitates the use of the errors.Is function for matching against RangeError.

Example:

if errors.Is(err, &comptime.RangeError{}) {
    // handle RangeError
}

func (*RangeError) Position

func (e *RangeError) Position() int

Position returns the position in the input string where the RangeError occurred. The position is 0-based, meaning that the first character in the input string is at position 0.

type SyntaxError

type SyntaxError struct {
	// contains filtered or unexported fields
}

SyntaxError represents an error that occurs during the parsing of a duration string. It provides details about the specific nature of the error and the position in the string where the error was detected.

func (*SyntaxError) Cause

func (e *SyntaxError) Cause() SyntaxErrorCause

Cause returns the specific cause of the SyntaxError. The cause provides details on the type of syntax error encountered, such as InvalidNumber, InvalidUnit, InvalidUnitOrder, or UnexpectedCharactersInSingleUnitMode.

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

Error implements the error interface for ParseError. It provides a formatted error message detailing the position and the nature of the parsing error. The position in the error message is converted to 1-based indexing, rather than the original 0-based indexing used in the input string.

func (*SyntaxError) Is

func (e *SyntaxError) Is(target error) bool

Is checks whether the provided target error matches the SyntaxError type. This method facilitates the use of the errors.Is function for matching against SyntaxError.

Example:

if errors.Is(err, &comptime.SyntaxError{}) {
    // handle SyntaxError
}

func (*SyntaxError) Position

func (e *SyntaxError) Position() int

Position returns the position in the input string where the SyntaxError occurred. The position is 0-based, meaning that the first character in the input string is at position 0.

type SyntaxErrorCause

type SyntaxErrorCause int

SyntaxErrorCause represents the cause of a syntax error during duration parsing. It discriminates between different kinds of syntax errors to aid in error handling and debugging.

const (
	// InvalidNumber indicates that a provided number in the
	// duration string is invalid or cannot be interpreted.
	InvalidNumber SyntaxErrorCause = iota + 1

	// InvalidUnit signifies that an unrecognised or unsupported
	// unit is used in the duration string.
	InvalidUnit

	// InvalidUnitOrder denotes an error when units in the
	// duration string are not in decreasing order of magnitude
	// (e.g., specifying minutes before hours).
	InvalidUnitOrder

	// UnexpectedCharactersInSingleUnitMode indicates that
	// unexpected characters were encountered beyond the first
	// valid duration when parsing in ParseModeSingleUnit. This
	// occurs when multiple unit-value pairs or extraneous
	// characters are found, which are not permitted in this mode.
	UnexpectedCharactersInSingleUnitMode
)

type Unit

type Unit uint

Unit is used to represent different time units (day, hour, minute, second, millisecond, microsecond) in numerical form. The zero value represents an invalid time unit.

const (
	Microsecond Unit = iota
	Millisecond
	Second
	Minute
	Hour
	Day
)

These constants represent different units of time used in the duration parsing process. They are ordered in increasing order of magnitude, from Microsecond to Day.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL