Skip to content

Commit

Permalink
improved clock package doc comments (as per Go 1.19)
Browse files Browse the repository at this point in the history
  • Loading branch information
rickb777 committed Jan 16, 2025
1 parent 159b969 commit e151289
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 55 deletions.
66 changes: 33 additions & 33 deletions clock/clock.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,54 @@ import (
"github.com/rickb777/period"
)

// Clock specifies a time of day. It complements the existing time.Duration, applying
// Clock specifies a time of day. It complements the existing [time.Duration], applying
// that to the time since midnight (on some arbitrary day in some arbitrary timezone).
// The resolution is to the nearest nanosecond, like time.Duration.
//
// It is not intended that Clock be used to represent periods greater than 24 hours nor
// negative values. However, for such lengths of time, a fixed 24 hours per day
// is assumed and a modulo operation Mod24 is provided to discard whole multiples of 24 hours.
// is assumed and a modulo operation [Clock.Mod24] is provided to discard whole multiples of 24 hours.
//
// Clock is a type of integer (actually int64), so values can be compared and sorted as
// per other integers. The constants Second, Minute, Hour and Day can be added and subtracted
// per other integers. The constants [Second], [Minute], [Hour] and [Day] can be added and subtracted
// with obvious outcomes.
//
// See https://en.wikipedia.org/wiki/ISO_8601#Times
type Clock int64

// Common durations - second, minute, hour and day.
const (
// Millisecond is one millisecond; it has a similar meaning to time.Millisecond.
// Millisecond is one millisecond; it has a similar meaning to [time.Millisecond].
Millisecond Clock = Clock(time.Millisecond)

// Second is one second; it has a similar meaning to time.Second.
// Second is one second; it has a similar meaning to [time.Second].
Second Clock = Clock(time.Second)

// Minute is one minute; it has a similar meaning to time.Minute.
// Minute is one minute; it has a similar meaning to [time.Minute].
Minute Clock = Clock(time.Minute)

// Hour is one hour; it has a similar meaning to time.Hour.
// Hour is one hour; it has a similar meaning to [time.Hour].
Hour Clock = Clock(time.Hour)

// Day is a fixed period of 24 hours. This does not take account of daylight savings,
// so is not fully general.
Day Clock = Clock(time.Hour * 24)
)

// Midnight is the zero value of a Clock.
// Midnight is the zero value of a [Clock].
const Midnight Clock = 0

// Noon is at 12pm.
const Noon Clock = Hour * 12

// Undefined is provided because the zero value of a Clock *is* defined (i.e. Midnight).
// So a special value is chosen, which is math.MinInt64.
// Undefined is provided because the zero value of a [Clock] *is* defined (i.e. [Midnight]).
// So a special value is chosen, which is [math.MinInt64].
const Undefined Clock = Clock(math.MinInt64)

//-------------------------------------------------------------------------------------------------

// New returns a new Clock with specified hour, minute, second and millisecond.
// To set sub-millisecond digits, chain this with AddDuration.
// New returns a new [Clock] with specified hour, minute, second and millisecond.
// To set sub-millisecond digits, chain this with [Clock.AddDuration].
func New(hour, minute, second, millisec int) Clock {
hx := Clock(hour) * Hour
mx := Clock(minute) * Minute
Expand All @@ -68,7 +68,7 @@ func New(hour, minute, second, millisec int) Clock {
return hx + mx + sx + ms
}

// NewAt returns a new Clock with specified hour, minute, seconds (to nanosecond resolution).
// NewAt returns a new [Clock] with specified hour, minute, seconds (to nanosecond resolution).
func NewAt(t time.Time) Clock {
hour, minute, second := t.Clock()
hx := Clock(hour) * Hour
Expand All @@ -78,20 +78,20 @@ func NewAt(t time.Time) Clock {
return hx + mx + sx + ns
}

// SinceMidnight returns a new Clock based on a duration since some arbitrary midnight.
// SinceMidnight returns a new [Clock] based on a duration since some arbitrary midnight.
func SinceMidnight(d time.Duration) Clock {
return Clock(d)
}

// DurationSinceMidnight convert a clock to a time.Duration since some arbitrary midnight.
// DurationSinceMidnight convert a [Clock] to a [time.Duration] since some arbitrary midnight.
func (c Clock) DurationSinceMidnight() time.Duration {
return time.Duration(c)
}

// Add returns a new Clock offset from this clock specified hour, minute, second and millisecond.
// Add returns a new [Clock] offset from this clock specified hour, minute, second and millisecond.
// The parameters can be negative.
//
// If required, use Mod24() to correct any overflow or underflow.
// If required, use [Clock.Mod24] to correct any overflow or underflow.
func (c Clock) Add(h, m, s, ms int) Clock {
hx := Clock(h) * Hour
mx := Clock(m) * Minute
Expand All @@ -100,18 +100,18 @@ func (c Clock) Add(h, m, s, ms int) Clock {
return c + hx + mx + sx + ns
}

// AddDuration returns a new Clock offset from this clock by a duration.
// AddDuration returns a new [Clock] offset from this clock by a duration.
// The parameter can be negative.
//
// If required, use Mod24() to correct any overflow or underflow.
// If required, use [Clock.Mod24] to correct any overflow or underflow.
func (c Clock) AddDuration(d time.Duration) Clock {
return c + Clock(d)
}

// AddPeriod returns a new Clock offset from this clock by a time period.
// AddPeriod returns a new [Clock] offset from this clock by a time period.
// The parameter can be negative.
//
// If required, use Mod24() to correct any overflow or underflow.
// If required, use [Clock.Mod24] to correct any overflow or underflow.
//
// The boolean flag is true when the result is precise and false if an
// approximation.
Expand All @@ -120,7 +120,7 @@ func (c Clock) AddPeriod(p period.Period) (Clock, bool) {
return c.AddDuration(d), precise
}

// ModSubtract returns the duration between two clock times.
// ModSubtract returns the duration between two [Clock] times.
//
// If c2 is before c (i.e. c2 < c), the result is the duration computed from c - c2.
//
Expand All @@ -135,7 +135,7 @@ func (c Clock) ModSubtract(c2 Clock) time.Duration {
//-------------------------------------------------------------------------------------------------

// IsInOneDay tests whether a clock time is in the range 0 to 24 hours, inclusive. Inside this
// range, a Clock is generally well-behaved. But outside it, there may be errors due to daylight
// range, a [Clock] is generally well-behaved. But outside it, there may be errors due to daylight
// savings. Note that 24:00:00 is included as a special case as per ISO-8601 definition of midnight.
func (c Clock) IsInOneDay() bool {
return Midnight <= c && c <= Day
Expand All @@ -149,7 +149,7 @@ func (c Clock) IsMidnight() bool {

// TruncateMillisecond discards any fractional digits within the millisecond represented by c.
// For example, for 10:20:30.456111222 this will return 10:20:30.456.
// This method will force the String method to limit its output to three decimal places.
// This method will force the [Clock.String] method to limit its output to three decimal places.
func (c Clock) TruncateMillisecond() Clock {
return (c / Millisecond) * Millisecond
}
Expand Down Expand Up @@ -177,49 +177,49 @@ func (c Clock) Mod24() Clock {

//-------------------------------------------------------------------------------------------------

// Days gets the number of whole days represented by the Clock, assuming that each day is a fixed
// 24 hour period. Negative values are treated so that the range -23h59m59s to -1s is fully
// Days gets the number of whole days represented by the [Clock], assuming that each day is a fixed
// 24-hour period. Negative values are treated so that the range -23h59m59s to -1s is fully
// enclosed in a day numbered -1, and so on. This means that the result is zero only for the
// clock range 0s to 23h59m59s, for which IsInOneDay() returns true.
// clock range 0s to 23h59m59s, for which [Clock.IsInOneDay] returns true.
func (c Clock) Days() int {
if c < Midnight {
return int(c/Day) - 1
}
return int(c / Day)
}

// Hour gets the clock-face number of hours (calculated from the modulo time, see Mod24).
// Hour gets the clock-face number of hours (calculated from the modulo time, see [Clock.Mod24]).
func (c Clock) Hour() int {
return int(clockHour(c.Mod24()))
}

// Minute gets the clock-face number of minutes (calculated from the modulo time, see Mod24).
// Minute gets the clock-face number of minutes (calculated from the modulo time, see [Clock.Mod24]).
// For example, for 22:35 this will return 35.
func (c Clock) Minute() int {
return int(clockMinute(c.Mod24()))
}

// Second gets the clock-face number of seconds (calculated from the modulo time, see Mod24).
// Second gets the clock-face number of seconds (calculated from the modulo time, see [Clock.Mod24]).
// For example, for 10:20:30 this will return 30.
func (c Clock) Second() int {
return int(clockSecond(c.Mod24()))
}

// Millisecond gets the clock-face number of milliseconds within the second specified by c
// (calculated from the modulo time, see Mod24), in the range [0, 999].
// (calculated from the modulo time, see [Clock.Mod24]), in the range [0, 999].
// For example, for 10:20:30.456 this will return 456.
func (c Clock) Millisecond() int {
return int(clockNanosecond(c.Mod24()) / 1_000_000)
}

// Nanosecond gets the clock-face number of nanoseconds within the second specified by c
// (calculated from the modulo time, see Mod24), in the range [0, 999999999].
// (calculated from the modulo time, see [Clock.Mod24]), in the range [0, 999999999].
// For example, for 10:20:30.456111222 this will return 456111222.
func (c Clock) Nanosecond() int {
return int(clockNanosecond(c.Mod24()))
}

// HourMinuteSecond gets the hours, minutes and seconds values (calculated from the modulo time, see Mod24).
// HourMinuteSecond gets the hours, minutes and seconds values (calculated from the modulo time, see [Clock.Mod24]).
func (c Clock) HourMinuteSecond() (int, int, int) {
c2 := c.Mod24()
return int(clockHour(c2)), int(clockMinute(c2)), int(clockSecond(c2))
Expand Down
16 changes: 8 additions & 8 deletions clock/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package clock
import "fmt"

// Hh gets the clock-face number of hours as a two-digit string.
// It is calculated from the modulo time; see Mod24.
// It is calculated from the modulo time; see [Clock.Mod24].
// Note the special case of midnight at the end of a day is "24".
func (c Clock) Hh() string {
if c == Day {
Expand All @@ -18,7 +18,7 @@ func (c Clock) Hh() string {
}

// HhMm gets the clock-face number of hours and minutes as a five-character ISO-8601 time string.
// It is calculated from the modulo time; see Mod24.
// It is calculated from the modulo time; see [Clock.Mod24].
// Note the special case of midnight at the end of a day is "24:00".
func (c Clock) HhMm() string {
if c == Day {
Expand All @@ -29,7 +29,7 @@ func (c Clock) HhMm() string {
}

// HhMmSs gets the clock-face number of hours, minutes, seconds as an eight-character ISO-8601 time string.
// It is calculated from the modulo time; see Mod24.
// It is calculated from the modulo time; see [Clock.Mod24].
// Note the special case of midnight at the end of a day is "24:00:00".
func (c Clock) HhMmSs() string {
if c == Day {
Expand All @@ -41,7 +41,7 @@ func (c Clock) HhMmSs() string {

// Hh12 gets the clock-face number of hours as a one- or two-digit string, followed by am or pm.
// Remember that midnight is 12am, noon is 12pm.
// It is calculated from the modulo time; see Mod24.
// It is calculated from the modulo time; see [Clock.Mod24].
func (c Clock) Hh12() string {
cm := c.Mod24()
h, sfx := clockHour12(cm)
Expand All @@ -50,7 +50,7 @@ func (c Clock) Hh12() string {

// HhMm12 gets the clock-face number of hours and minutes, followed by am or pm.
// Remember that midnight is 12am, noon is 12pm.
// It is calculated from the modulo time; see Mod24.
// It is calculated from the modulo time; see [Clock.Mod24].
func (c Clock) HhMm12() string {
cm := c.Mod24()
h, sfx := clockHour12(cm)
Expand All @@ -59,7 +59,7 @@ func (c Clock) HhMm12() string {

// HhMmSs12 gets the clock-face number of hours, minutes and seconds, followed by am or pm.
// Remember that midnight is 12am, noon is 12pm.
// It is calculated from the modulo time; see Mod24.
// It is calculated from the modulo time; see [Clock.Mod24].
func (c Clock) HhMmSs12() string {
cm := c.Mod24()
h, sfx := clockHour12(cm)
Expand All @@ -69,13 +69,13 @@ func (c Clock) HhMmSs12() string {
// String gets the clock-face number of hours, minutes, seconds and fraction as an ISO-8601 time
// string.
//
// If the clock value has more than 24 hours, the excess is discarded (see Mod24).
// If the clock value has more than 24 hours, the excess is discarded (see [Clock.Mod24]).
//
// The number of decimal places depends on the clock value. If microsecond and nanosecond digits
// are non-zero, the result is given to nanosecond precision. Otherwise, a shorter form is used that
// only has millisecond precision.
//
// See TruncateMillisecond to obtain the shorter form always.
// See [Clock.TruncateMillisecond] to obtain the shorter form always.
//
// The special case of midnight at the end of a day is "24:00:00.000".
func (c Clock) String() string {
Expand Down
8 changes: 4 additions & 4 deletions clock/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import (
"fmt"
)

// MarshalBinary implements the encoding.BinaryMarshaler interface.
// MarshalBinary implements the [encoding.BinaryMarshaler] interface.
func (c Clock) MarshalBinary() (b []byte, err error) {
b = make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(c))
return b, nil
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
// UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface.
func (c *Clock) UnmarshalBinary(data []byte) error {
switch len(data) {
case 0:
Expand All @@ -27,12 +27,12 @@ func (c *Clock) UnmarshalBinary(data []byte) error {
return nil
}

// MarshalText implements the encoding.TextMarshaler interface.
// MarshalText implements the [encoding.TextMarshaler] interface.
func (c Clock) MarshalText() ([]byte, error) {
return []byte(c.String()), nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
func (c *Clock) UnmarshalText(data []byte) (err error) {
clock, err := Parse(string(data))
if err == nil {
Expand Down
8 changes: 5 additions & 3 deletions clock/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"strings"
)

// MustParse is as per Parse except that it panics if the string cannot be parsed.
// MustParse is as per [Parse] except that it panics if the string cannot be parsed.
// This is intended for setup code; don't use it for user inputs.
func MustParse(hms string) Clock {
t, err := Parse(hms)
Expand All @@ -21,11 +21,13 @@ func MustParse(hms string) Clock {
return t
}

// Parse converts a string representation to a Clock. Acceptable representations
// are as per ISO-8601 - see https://en.wikipedia.org/wiki/ISO_8601#Times
// Parse converts a string representation to a [Clock]. Acceptable representations
// are as per [ISO-8601].
//
// Also, conventional AM- and PM-based strings are parsed, such as "2am", "2:45pm".
// Remember that 12am is midnight and 12pm is noon.
//
// [ISO-8601]: https://en.wikipedia.org/wiki/ISO_8601#Times
func Parse(hms string) (clock Clock, err error) {
if strings.HasSuffix(hms, "am") || strings.HasSuffix(hms, "AM") {
return parseAmPm(hms, 0)
Expand Down
12 changes: 5 additions & 7 deletions clock/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import (
"time"
)

// Scan parses some value. It implements sql.Scanner,
// https://golang.org/pkg/database/sql/#Scanner
// Scan parses some value. It implements [sql.Scanner].
func (c *Clock) Scan(value interface{}) (err error) {
if value == nil {
return nil
Expand All @@ -33,22 +32,21 @@ func (c *Clock) scanAny(value interface{}) (err error) {
return
}

// Value converts the value to an int64 or a string. It implements driver.Valuer,
// Value converts the value to an int64 or a string. It implements [driver.Valuer].
// Alter the representation by altering the Valuer function.
// https://golang.org/pkg/database/sql/driver/#Valuer
func (c Clock) Value() (driver.Value, error) {
return Valuer(c), nil
}

// Valuer is a pluggable function for writing Clock values to a DB.
// Valuer is a pluggable function for writing [Clock] values to a DB.
var Valuer = ValueAsNumber

// ValueAsNumber simply returns the numeric value of a Clock.
// ValueAsNumber simply returns the numeric value of a [Clock].
func ValueAsNumber(c Clock) driver.Value {
return int64(c)
}

// ValueAsString returns the string value of a Clock.
// ValueAsString returns the string value of a [Clock].
func ValueAsString(c Clock) driver.Value {
return c.String()
}

0 comments on commit e151289

Please sign in to comment.