cal

package module
v2.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2021 License: BSD-3-Clause Imports: 1 Imported by: 31

README

cal/v2: Go (golang) calendar library for dealing with holidays and work days

This library augments the Go time package to provide easy handling of holidays and work days (business days).

Holiday instances are calculated from either builtin or user-created functions to support exact days, floating days such as the 3rd Monday of the month, yearly offsets such as the 100th day of the year, or more complex rules such as offsets from Easter. Holidays may provide separate actual and observed dates for cases where holidays are celebrated on an alternate day if they fall on a specific day of the week (usually weekends).

The Calendar type provides the basic functionality for creating a yearly calendar with holidays.

BusinessCalendar adds additional functionality for calculating workdays and hours worked.

Differences from v1

For v2, much of the functionality of this library was rewritten to address shortcomings of the v1 releases. This version provides the following benefits over v1:

  • Holidays
    • Observation rules are tied to individual holidays rather than a per-calendar setting
    • Name, description, and observance type fields added
    • Starting, ending, and exception year options
    • Holiday definitions are separated into subpackages by ISO code (no longer necessary to bundle all holidays in the final binary)
  • Calendar
    • Separation of business specific functionality into BusinessCalendar
    • Name and description fields added
    • Support for time.Location matching to ease use of multiple Calendars
  • BusinessCalendar
    • Full support for working hours and related calculations
    • Work days and work start and end times can be provided by custom functions

Example

Here is a simple usage example of a cron job that runs once per day:

package main

import (
	"time"

	"github.com/rickar/cal/v2"
	"github.com/rickar/cal/v2/us"
)

func main() {
	c := cal.NewBusinessCalendar()
	c.Name = "Bigco, Inc."
	c.Description = "Default company calendar"

	// add holidays that the business observes
	c.AddHoliday(
		us.NewYear,
		us.MemorialDay,
		us.IndependenceDay,
		us.LaborDay,
		us.ThanksgivingDay,
		us.ChristmasDay,
	)

	// change the default of a Mon - Fri, 9am-5pm work week
	c.SetWorkday(time.Saturday, true)
	c.SetWorkHours(8*time.Hour, 18*time.Hour+30*time.Minute)

	t := time.Now()

	// run different batch processing jobs based on the day

	if c.IsWorkday(t) {
		// create daily activity reports
	}

	if cal.IsWeekend(t) {
		// validate employee time submissions
	}

	if c.WorkdaysRemain(t) == 10 {
		// 10 business days before the end of month
		// send account statements to customers
	}

	if c.WorkdaysRemain(t) == 0 {
		// last business day of the month
		// execute auto billing transfers
	}

	// determine the number of working hours left in the current month
	nextMonth := cal.DayStart(cal.MonthStart(t.AddDate(0, 1, 0)))
	hoursLeft := c.WorkHoursInRange(t, nextMonth)

	// check if there are any tasks for this month that are in danger of missing their deadline
	pendingTasks := []struct{ pendingHours time.Duration }{{pendingHours: 32}} // assumed to be fetched from a DB or API
	for _, task := range pendingTasks {
		if hoursLeft < task.pendingHours {
			// send alert to management
		}
	}
}

Documentation

Overview

Package cal provides extensions to the time package for handling holidays, work days (business days), and working hours.

Standard holidays for countries are found in subpackages by ISO code.

Work days and working hours can be customized per calendar to match the needs of the business.

As in the time package, all calculations assume a Gregorian calendar.

Index

Constants

This section is empty.

Variables

View Source
var DefaultLoc = time.Local

DefaultLoc is the default time.Location to use in functions that do not require a full time.Time value.

Functions

func CalcDayOfMonth

func CalcDayOfMonth(h *Holiday, year int) time.Time

CalcDayOfMonth calculates the occurrence of a holiday that is always a specific day of the month such as the 5th of November.

func CalcEasterOffset

func CalcEasterOffset(h *Holiday, year int) time.Time

CalcEasterOffset calculates the occurrence of a holiday that is determined by its relation to the Easter holiday.

func CalcWeekdayFrom

func CalcWeekdayFrom(h *Holiday, year int) time.Time

CalcWeekdayFrom calculates the occurrence of a holiday that falls on a specific day of the week following a starting date.

func CalcWeekdayOffset

func CalcWeekdayOffset(h *Holiday, year int) time.Time

CalcWeekdayOffset calculates the occurrence of a holiday that falls on the nth occurrence of a weekday in a month, such as the third wednesday of July.

func DayEnd

func DayEnd(t time.Time) time.Time

DayEnd reports the end of the day in t (sets time fields to maximum).

func DayStart

func DayStart(t time.Time) time.Time

DayStart reports the start of the day in t (sets time fields zero).

func IsWeekdayN

func IsWeekdayN(t time.Time, day time.Weekday, n int) bool

IsWeekdayN reports whether the given date is the nth occurrence of the day in the month.

The value of n is handled the same way as WeekdayNFrom.

If n is larger than the number of occurrences of the weekday in the month, the result will be false.

func IsWeekend

func IsWeekend(t time.Time) bool

IsWeekend reports whether the given time falls on a weekend.

func JulianDate

func JulianDate(t time.Time) float64

JulianDate reports the Julian Date (which includes time as a fraction) for t.

func JulianDayNumber

func JulianDayNumber(t time.Time) int

JulianDayNumber reports the Julian Day Number for t. Note that Julian days start at 12:00 UTC.

func MaxTime

func MaxTime(ts ...time.Time) time.Time

MaxTime reports the maximum time in the given list. If the list is empty, the zero value is returned.

func MinTime

func MinTime(ts ...time.Time) time.Time

MinTime reports the minimum time in the given list. If the list is empty, the zero value is returned.

func ModifiedJulianDate

func ModifiedJulianDate(t time.Time) float64

ModifiedJulianDate reports the modified Julian Date Number for t. Note that modified Julian days start at 00:00 UTC.

func ModifiedJulianDayNumber

func ModifiedJulianDayNumber(t time.Time) int

ModifiedJulianDayNumber reports the modified Julian Day Number for t. Note that modified Julian days start at 00:00 UTC.

func MonthEnd

func MonthEnd(t time.Time) time.Time

MonthEnd reports the ending day of the month in t. The time portion is unchanged.

func MonthStart

func MonthStart(t time.Time) time.Time

MonthStart reports the starting day of the month in t. The time portion is unchanged.

func ReplaceLocation

func ReplaceLocation(t time.Time, loc *time.Location) time.Time

ReplaceLocation returns a copy of the given time in the given location without changing the time of day.

func WeekdayN

func WeekdayN(year int, month time.Month, day time.Weekday, n int) time.Time

WeekdayN reports the nth occurrence of a weekday starting in the given year and month.

The value of n is handled the same way as WeekdayNFrom.

If n is larger than the number of occurrences of the weekday in the month, counting will continue into the following month(s) until the nth occurrence is found. For example, n=52 would report the first occurrence a year away.

All non-zero results will be at noon in the DefaultLoc location/timezone.

func WeekdayNFrom

func WeekdayNFrom(t time.Time, day time.Weekday, n int) time.Time

WeekdayNFrom reports the nth occurrence of a weekday starting from the given time.

The value of n affects the direction of counting:

n > 0: the result is the nth occurrence counting forwards from the
  given time.
n == 0: the result is always the zero time.
n < 0: the result is the nth occurrence counting backwards from the
  given time.

The given time is considered an occurrence of the weekday; if n == 1 or -1 and the given time matches the desired weekday, it will be returned unchanged.

For non-zero results the time of day will be unchanged from the given time.

Types

type AltDay

type AltDay struct {
	Day    time.Weekday // the day to match
	Offset int          // the number of days to move the observance forward (positive) or backward (negative)
}

AltDay represents an alternative day to observe a holiday.

type BusinessCalendar

type BusinessCalendar struct {
	WorkdayFunc WorkdayFn // optional function to override workday flags

	WorkdayStartFunc WorkdayStartFn // optional function to override workday start time

	WorkdayEndFunc WorkdayEndFn // optional function to override workday end time

	Calendar
	// contains filtered or unexported fields
}

BusinessCalendar represents a calendar used for business purposes.

func NewBusinessCalendar

func NewBusinessCalendar() *BusinessCalendar

NewBusinessCalendar creates a new BusinessCalendar with no holidays defined and work days of Monday through Friday from 9am-5pm.

func (*BusinessCalendar) AddWorkHours

func (c *BusinessCalendar) AddWorkHours(date time.Time, worked time.Duration) time.Time

AddWorkHours determines the time in the future where the worked hours will be completed.

If duration <= 0, then the original date is returned.

func (*BusinessCalendar) IsWorkTime

func (c *BusinessCalendar) IsWorkTime(date time.Time) bool

IsWorkTime reports whether a given date and time is within working hours.

func (*BusinessCalendar) IsWorkday

func (c *BusinessCalendar) IsWorkday(date time.Time) bool

IsWorkday reports whether a given date is a work day (business day).

func (*BusinessCalendar) NextWorkdayStart

func (c *BusinessCalendar) NextWorkdayStart(date time.Time) time.Time

NextWorkdayStart reports the start of the next work day from the given date.

func (*BusinessCalendar) SetWorkHours

func (c *BusinessCalendar) SetWorkHours(start time.Duration, end time.Duration)

SetWorkHours sets the start and end times for a workday.

Only hours and minutes will be considered. The time component of start should be less than the time component of end.

func (*BusinessCalendar) SetWorkday

func (c *BusinessCalendar) SetWorkday(day time.Weekday, workday bool)

SetWorkday changes the given day's status as a standard working day

func (*BusinessCalendar) WorkHours

func (c *BusinessCalendar) WorkHours(date time.Time) time.Duration

WorkHours reports the number of working hours for the given day.

func (*BusinessCalendar) WorkHoursInRange

func (c *BusinessCalendar) WorkHoursInRange(start, end time.Time) time.Duration

WorkHoursInRange reports the working hours between the given start and end dates.

func (*BusinessCalendar) WorkdayEnd

func (c *BusinessCalendar) WorkdayEnd(date time.Time) time.Time

WorkdayEnd reports the time at which work ends in the given day. If the day is not a workday, the zero time is returned.

func (*BusinessCalendar) WorkdayN

func (c *BusinessCalendar) WorkdayN(year int, month time.Month, n int) int

WorkdayN reports the day of the month that corresponds to the nth workday for the given year and month.

The value of n affects the direction of counting:

n > 0: counting begins at the first day of the month.
n == 0: the result is always 0.
n < 0: counting begins at the end of the month.

func (*BusinessCalendar) WorkdayStart

func (c *BusinessCalendar) WorkdayStart(date time.Time) time.Time

WorkdayStart reports the time at which work starts in the given day. If the day is not a workday, the zero time is returned.

func (*BusinessCalendar) WorkdaysFrom

func (c *BusinessCalendar) WorkdaysFrom(start time.Time, offset int) time.Time

WorkdaysFrom reports the date of a workday that is offset days away from start.

If n > 0, then the date returned is start + offset workdays. If n == 0, then the date is returned unchanged. If n < 0, then the date returned is start - offset workdays.

func (*BusinessCalendar) WorkdaysInMonth

func (c *BusinessCalendar) WorkdaysInMonth(year int, month time.Month) int

WorkdaysInMonth reports the total number of workdays for the given year and month.

func (*BusinessCalendar) WorkdaysInRange

func (c *BusinessCalendar) WorkdaysInRange(start, end time.Time) int

WorkdaysInRange reports the number of workdays between the start and end times (inclusive).

func (*BusinessCalendar) WorkdaysRemain

func (c *BusinessCalendar) WorkdaysRemain(date time.Time) int

WorkdaysRemain reports the total number of remaining workdays in the month for the given date.

type Calendar

type Calendar struct {
	Name        string           // calendar short name
	Description string           // calendar description
	Locations   []*time.Location // locations where the calendar applies
	Holidays    []*Holiday       // applicable holidays for this calendar
}

Calendar represents a basic yearly calendar with a list of holidays.

func (*Calendar) AddHoliday

func (c *Calendar) AddHoliday(h ...*Holiday)

AddHoliday adds a holiday to the calendar's list.

func (*Calendar) IsApplicable

func (c *Calendar) IsApplicable(loc *time.Location) bool

IsApplicable reports whether the calendar is applicable for the given location.

If no locations have been specified for the calendar, true is returned.

func (*Calendar) IsHoliday

func (c *Calendar) IsHoliday(date time.Time) (actual, observed bool, h *Holiday)

IsHoliday reports whether a given date is a holiday or an observation day.

type Holiday

type Holiday struct {
	Name        string         // name in local language
	Description string         // further details/notes
	Type        ObservanceType // type of day being observed
	StartYear   int            // the first year the holiday is observed
	EndYear     int            // the last year the holiday is observed
	Except      []int          // years where the holiday doesn't apply

	// calculation fields; required fields depend on rule being followed
	Month      time.Month   // the month the holiday occurs
	Day        int          // the day the holiday occurs
	Weekday    time.Weekday // the weekday the holiday occurs
	Offset     int          // the weekday or start date offset the holiday occurs
	CalcOffset int          // days offset from the date the holiday occurs, applied after the calculation
	Julian     bool         // the holiday is based on a Julian calendar
	Observed   []AltDay     // the substitution days for the holiday
	Func       HolidayFn    // logic used to determine occurrences
}

Holiday holds information about the type and occurrence of a holiday.

func (*Holiday) Calc

func (h *Holiday) Calc(year int) (actual, observed time.Time)

Calc reports the actual and observed dates of a holiday for the given year. If the holiday is not observed in the given year, the zero time is returned.

Returned times are the start of the day in the system location.

func (*Holiday) Clone

func (h *Holiday) Clone(overrides *Holiday) *Holiday

Clone returns a copy of the Holiday. If overrides is non-nil, then the field values set in overrides will be used instead of the original values.

The following fields can be set in overrides: Name, Description, Type, StartYear, EndYear, Except, Observed.

type HolidayFn

type HolidayFn func(h *Holiday, year int) time.Time

HolidayFn calculates the expected occurrence of a holiday for the given year. Returned times are the start of the day in the system location.

Note that implementations of this function should always return the day that the holiday is expected to occur. Additional rules for substitution days and exception years will be applied by Holiday.Calc().

type ObservanceType

type ObservanceType uint8

ObservanceType represents the type of holiday or special day being observed.

const (
	ObservanceUnknown   ObservanceType = iota // value not set or not applicable
	ObservancePublic                          // public / national / regional holiday
	ObservanceBank                            // bank holiday
	ObservanceReligious                       // religious holiday
	ObservanceOther                           // all other holidays (school, work, etc.)
)

Allowed values for ObservanceType

type WorkdayEndFn

type WorkdayEndFn func(date time.Time) time.Time

WorkdayEndFn reports the end of the workday for the given date. This is useful for situations where work days have different end times throughout the year.

If your workdays end at the same time every day then a WorkdayEndFn is not necessary and you can use SetWorkingHours() instead.

type WorkdayFn

type WorkdayFn func(date time.Time) bool

WorkdayFn reports whether the given date is a workday. This is useful for situations where work days change throughout the year.

If your workdays are fixed (Mon-Fri for example) then a WorkdayFn is not necessary and you can use SetWorkday() instead.

type WorkdayStartFn

type WorkdayStartFn func(date time.Time) time.Time

WorkdayStartFn reports the start of the workday for the given date. This is useful for situations where work days have different start times throughout the year.

If your workdays start at the same time every day then a WorkdayStartFn is not necessary and you can use SetWorkingHours() instead.

Directories

Path Synopsis
Package aa provides common holiday definitions that are frequently used.
Package aa provides common holiday definitions that are frequently used.
Package at provides holiday definitions for Austria.
Package at provides holiday definitions for Austria.
Package au provides holiday definitions for Australia.
Package au provides holiday definitions for Australia.
Package be provides holiday definitions for Belgium.
Package be provides holiday definitions for Belgium.
Package ie provides holiday definitions for Brazil.
Package ie provides holiday definitions for Brazil.
Package ca provides holiday definitions for Canada.
Package ca provides holiday definitions for Canada.
Package ch provides holiday definitions for Switzerland.
Package ch provides holiday definitions for Switzerland.
Package cz provides holiday definitions for the Czech Republic.
Package cz provides holiday definitions for the Czech Republic.
Package de provides holiday definitions for Germany.
Package de provides holiday definitions for Germany.
Package dk provides holiday definitions for Denmark.
Package dk provides holiday definitions for Denmark.
Package ecb provides holiday definitions for the European Central Bank.
Package ecb provides holiday definitions for the European Central Bank.
Package es provides holiday definitions for Spain.
Package es provides holiday definitions for Spain.
Package fr provides holiday definitions for France.
Package fr provides holiday definitions for France.
Package gb provides holiday definitions for the United Kingdom.
Package gb provides holiday definitions for the United Kingdom.
Package ie provides holiday definitions for the Republic Of Ireland.
Package ie provides holiday definitions for the Republic Of Ireland.
Package it provides holiday definitions for Italy.
Package it provides holiday definitions for Italy.
Package nl provides holiday definitions for the Netherlands.
Package nl provides holiday definitions for the Netherlands.
Package no provides holiday definitions for Norway.
Package no provides holiday definitions for Norway.
Package nz provides holiday definitions for New Zealand.
Package nz provides holiday definitions for New Zealand.
Package pl provides holiday definitions for Poland.
Package pl provides holiday definitions for Poland.
Package se provides holiday definitions for Sweden.
Package se provides holiday definitions for Sweden.
Package si provides holiday definitions for Slovenia.
Package si provides holiday definitions for Slovenia.
Package sk provides holiday definitions for Slovakia.
Package sk provides holiday definitions for Slovakia.
Package ua provides holiday definitions for Ukraine.
Package ua provides holiday definitions for Ukraine.
Package us provides holiday definitions for the United States of America.
Package us provides holiday definitions for the United States of America.
Package za provides holiday definitions for South Africa.
Package za provides holiday definitions for South Africa.

Jump to

Keyboard shortcuts

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