Skip to content

Commit

Permalink
Tests (and code corrections)
Browse files Browse the repository at this point in the history
And tag initial release
  • Loading branch information
danhunsaker committed Mar 26, 2018
1 parent 94041d1 commit df245dc
Show file tree
Hide file tree
Showing 17 changed files with 2,120 additions and 64 deletions.
19 changes: 19 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
language: go

go:
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- tip

before_install:
- go get -t -v ./...

script:
- ./go.test.sh

after_success:
- bash <(curl -s https://codecov.io/bash)
227 changes: 226 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

[![Software License](https://img.shields.io/github/license/danhunsaker/calends.svg?style=flat-square)](LICENSE)
[![Gitter](https://img.shields.io/gitter/room/danhunsaker/calends.svg?style=flat-square)](https://gitter.im/danhunsaker/calends)
[![GoDoc Documentation](https://img.shields.io/badge/GoDoc-documentation-blue.svg?style=flat-square)](https://godoc.org/github.com/danhunsaker/calends)

[![Latest Stable Version](https://img.shields.io/github/release/danhunsaker/calends.svg?label=stable&style=flat-square)](https://github.com/danhunsaker/calends/releases)
[![Latest Unstable Version](https://img.shields.io/github/release/danhunsaker/calends/all.svg?label=unstable&style=flat-square)](https://github.com/danhunsaker/calends/releases)
Expand Down Expand Up @@ -120,7 +121,231 @@ the library ever need to touch. Another is the `TAI64NAXURTime` class, used to
store and manipulate the instants of time which make up a `Calends` instance.
The rest are interfaces for extending the library's functionality.

_**.TODO.**_
`Calends` objects are immutable - all methods return a new `Calends` object
where they might otherwise alter the current one. This is true even of the
`Set*()` methods. This has the side effect of using more memory to perform
manipulations than updating values on an existing object would. It makes many
operations safer, though, than mutable objects would allow.

Language-specific documentation is available, and may give a more concrete idea
of how to use Calends in a given language/environment, but the general usage
information given here should be valid for all of them.

### Create

- `calends.Create(value, calendar, format)`

Creates a new `Calends` object, using `calendar` to select a calendar system,
and `format` to parse the contents of `value` into the `Calends` object's
internal instants. The contents of `value` can vary based on the calendar
system itself, but generally speaking can always be a string. In any case, the
value can always be a string→value map (associative array, hash, or whatever
your language of choice prefers to call it), where the keys are any two of
`start`, `end`, and `duration`. If all three are provided, `duration` is
ignored in favor of calculating it directly. If only one is provided, `value`
is passed to the calendar system itself unchanged. The calendar system then
converts `value` to a `TAI64TAI64NAXURTime` instant, which the `Calends`
object sets to the appropriate internal value.

### Read

- `c.Date(calendar, format)` / `c.EndDate(calendar, format)`

Retrieves the start or end date of the `Calends` object `c` as a string. The
value is generated by the calendar system given in `calendar`, according to
the format string in `format`.

- `c.Duration()`

Retrieves the duration of the `Calends` object `c` as an arbitrary-precision
floating point number. This value will be `0` if the `Calends` object is an
instant.

### Update

- `c.SetDate(value, calendar, format)` / `c.SetEndDate(value, calendar, format)`

Sets the start or end date of a `Calends` object, based on the `Calends`
object `c`. The inputs are the same as for `Create()`, above, except the
string→value map option isn't available, since you're already specifically
setting the start or end value explicitly, depending on which method you call.

- `c.SetDuration(duration, calendar)` / `c.SetDurationFromEnd(duration, calendar)`

Sets the duration of a `Calends` object, adjusting the end or start point
accordingly, based on the `Calends` object `c`. The `duration` value is
interpreted by the calendar system given in `calendar`, so is subject to any
of its rules. `SetDurationFromEnd()` will adjust the start point, using the
end as the anchor for the duration.

### Manipulate

- `c.Add(offset, calendar)` / `c.AddFromEnd(offset, calendar)`

Increases the corresponding date in the `Calends` object `c` by `offset`, as
interpreted by the calendar system given in `calendar`.

- `c.Subtract(offset, calendar)` / `c.SubtractFromEnd(offset, calendar)`

Works the same as `Add()` / `AddFromEnd()`, except it decreases the
corresponding date, rather than increasing it.

- `c.Next(offset, calendar)` / `c.Previous(offset, calendar)`

Returns a `Calends` object of `offset` duration (as interpreted by the
calendar system given in `calendar`), which abuts the `Calends` object `c`. If
`offset` is empty, `calendar` is ignored, and the duration of `c` is used
instead.

### Combine

- `c1.Merge(c2)`

Returns a `Calends` object spanning from the earliest start date to the latest
end date between `Calends` objects `c1` and `c2`.

- `c1.Intersect(c2)`

Returns a `Calends` object spanning the overlap between `Calends` objects `c1`
and `c2`. If `c1` and `c2` don't overlap, returns an error.

- `c1.Gap(c2)`

Returns a `Calends` object spanning the gap between `Calends` objects `c1` and
`c2`. If `c1` and `c2` overlap (and there is, therefore, no gap to return),
returns an error.

### Compare

- `c1.Difference(c2, mode)`

Returns the difference of `Calends` object `c1` minus `c2`, using `mode` to
select which values to use in the calculation. Valid `mode`s include:

- `start` - use the start date of both `c1` and `c2`
- `duration` - use the duration of both `c1` and `c2`
- `end` - use the end date of both `c1` and `c2`
- `start-end` - use the start of `c1`, and the end of `c2`
- `end-start` - use the end of `c1`, and the start of `c2`

- `c1.Compare(c2, mode)`

Returns `-1` if `Calends` object `c1` is less than `Calends` object `c2`, `0`
if they are equal, and `1` if `c1` is greater than `c2`, using `mode` to
select which values to use in the comparison. Valid modes are the same as for
`Difference()`, above.

- `c1.Contains(c2)`

Returns a boolean value indicating whether `Calends` object `c1` contains all
of `Calends` object `c2`.

- `c1.Overlaps(c2)`

Returns a boolean value indicating whether `Calends` object `c1` overlaps with
`Calends` object `c2`.

- `c1.Abuts(c2)`

Returns a boolean value indicating whether `Calends` object `c1` abuts
`Calends` object `c2` (that is, whether one begins at the same instant the
other ends).

- `c1.IsSame(c2)`

Returns a boolean value indicating whether `Calends` object `c1` covers the
same span of time as `Calends` object `c2`.


- `c1.IsShorter(c2)` / `c1.IsSameDuration(c2)` / `c1.IsLonger(c2)`

Returns a boolean comparing the duration of `Calends` objects `c1` and `c2`.

- `c1.IsBefore(c2)` / `c1.StartsBefore(c2)` / `c1.EndsBefore(c2)`

Returns a boolean comparing `Calends` object `c1` with the start date of
`Calends` object `c2`. `IsBefore` compares the entirety of `c1` with `c2`;
`StartsBefore` compares only the start date of `c1`; `EndsBefore` compares
only the end date of `c1`.

- `c1.IsDuring(c2)` / `c1.StartsDuring(c2)` / `c1.EndsDuring(c2)`

Returns a boolean indicating whether `Calends` object `c1` lies between the
start and end dates of `Calends` object `c2`. `IsDuring` compares the entirety
of `c1` with `c2`; `StartsDuring` compares only the start date of `c1`;
`EndsDuring` compares only the end date of `c1`.

- `c1.IsAfter(c2)` / `c1.StartsAfter(c2)` / `c1.EndsAfter(c2)`

Returns a boolean comparing `Calends` object `c1` with the end date of
`Calends` object `c2`. `IsAfter` compares the entirety of `c1` with `c2`;
`StartsAfter` compares only the start date of `c1`; `EndsAfter` compares only
the end date of `c1`.

### Calendar Systems

Currently supported calendar systems, and the options available for each, are
listed below. Formats in **bold** are the default format for that calendar.

- `tai64`
- Formats
- Calends `TAI64NAXURTime` object _(input only)_
- string with TAI instant representation in one of the following layouts:
- `decimal` - number of seconds since 1970.01.01 00:00:00 TAI
- `tai64` - TAI64 External Representation; the hexadecimal version of
`decimal` plus 2^62, with no fractional seconds (16 hexits total)
- `tai64n` - TAI64N External Representation; `tai64` with 9 decimal places
encoded as 8 additional hexadecimal digits (24 hexits total)
- `tai64na` - TAI64NA External Representation; `tai64n` with 9 more
decimal places (18 total) encoded as 8 additional hexadecimal digits (32
hexits total)
- `tai64nax` - TAI64NAX External Representation; `tai64na` with 9 more
decimal places (27 total) encoded as 8 additional hexadecimal digits (40
hexits total)
- `tai64naxu` - TAI64NAXU External Representation; `tai64nax` with 9 more
decimal places (36 total) encoded as 8 additional hexadecimal digits (48
hexits total)
- **`tai64naxur` - TAI64NAXUR External Representation; `tai64naxu` with 9
more decimal places (45 total) encoded as 8 additional hexadecimal
digits (56 hexits total)**
- Offsets
- Calends `TAI64NAXURTime` object
- arbitrary-precision floating point number of seconds
- string with `decimal` format layout (above)

- `unix`
- Formats
- **number of seconds since 1970-01-01 00:00:00 UTC**
- input can be integer or float, in either numeric or string representation
- output uses Golang `fmt.Print()` conventions
- Offsets
- number of seconds
- same input formatting as above

- `gregorian`
- Formats
- Golang `time.Time` object _(input only)_
- Golang `time` package format strings (**RFC1123 layout**)
- C-style `strptime()`/`strftime()` format strings
- Offsets
- Golang `time.Duration` object
- string with Gregorian time units
- must be relative times
- use full words instead of abbreviations for time units (such as
`seconds` instead of just `s`)

## Contributing

Pull requests are always welcome! That said, please be open to discussing the PR
content, and possibly revising it if requested. Not all requests can be merged,
and not all changes are desired.

## Security Reporting

Report all security-related issues to [dan (dot) hunsaker (plus) calends (at)
gmail]([email protected]), and use PGP or GPG protections on your
message. Security issues will be addressed internally before making any
vulnerability announcements.

[GitHub]:https://github.com/danhunsaker/calends
[TAI64]:http://cr.yp.to/libtai/tai64.html
15 changes: 9 additions & 6 deletions calendars/0calendars.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,7 @@ parsing or formatting.
*/
func RegisterClass(name string, definition CalendarDefinition, defaultFormat string) {
registeredCalendars[canonCalendarName(name)] = calendarRegistration{
ToInternal: definition.ToInternal,
FromInternal: definition.FromInternal,
Offset: definition.Offset,
DefaultFormat: defaultFormat,
}
RegisterElements(name, definition.ToInternal, definition.FromInternal, definition.Offset, defaultFormat)
}

// RegisterElements registers a calendar system from its distinct functions.
Expand Down Expand Up @@ -107,6 +102,10 @@ func ToInternal(calendar string, date interface{}, format string) (TAI64NAXURTim
return TAI64NAXURTime{}, UnknownCalendarError
}

if format == "" {
format = DefaultFormat(calendar)
}

// fmt.Printf("ToInternal: %#v (%#v) [%#v]\n", canonCalendarName(calendar), format, date)

return registeredCalendars[canonCalendarName(calendar)].ToInternal(date, format)
Expand All @@ -118,6 +117,10 @@ func FromInternal(calendar string, stamp TAI64NAXURTime, format string) (string,
return "", UnknownCalendarError
}

if format == "" {
format = DefaultFormat(calendar)
}

// fmt.Printf("FromInternal: %#v (%#v) [%#v]\n", canonCalendarName(calendar), format, stamp)

return registeredCalendars[canonCalendarName(calendar)].FromInternal(stamp, format)
Expand Down
Loading

0 comments on commit df245dc

Please sign in to comment.