trips

package
v0.7.8 Latest Latest
Warning

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

Go to latest
Published: Mar 18, 2025 License: MIT Imports: 8 Imported by: 0

README

Trips package

Background

This package helps calculate if foreign visitors' trips to Schengen countries conform with Regulation (EU) No 610/2013 of 26 June 2013 limiting the total length of all trips to Schengen states to no more than 90 days in any 180 day period.

The date of entry should be considered as the first day of stay on the territory of the Member States and the date of exit should be considered as the last day of stay on the territory of the Member States.

For more details on the Regulation and its application please see https://ec.europa.eu/assets/home/visa-calculator/docs/short_stay_schengen_calculator_user_manual_en.pdf.

The calculation provided by this package uses a moving window configured in days over the trips provided to find the maximum length of days, inclusive of trip start and end dates, taken by the trips to learn if these breach the permissible length of stay. Trips cannot overlap in time.

Example

The example below is taken from example_test.go. Note that the last line of output is wrapped for readability

package trips

import (
    "fmt"
    "log"
    "net/url"
)

func Example() {

    // package variables
    WindowMaxDays = 180      // maximum window of days to calculate over
    CompoundStayMaxDays = 90 // longest allowed compound trip length in days

    // fail immediately on error
    fe := func(err error) {
        if err != nil {
            log.Fatal(err)
        }
    }

    // add trips by url
    url, _ := url.ParseRequestURI(
        "http://test.com/?" +
            "Start=2022-01-01&End=2022-01-01&" +
            "Start=2023-01-10&End=2023-02-08&" +
            "Start=2023-02-11&End=2023-04-04&" +
            "Start=2023-07-01&End=2023-07-30&" +
            "Start=2024-06-10&End=2024-06-14",
    )
    _, err := HolidaysURLDecoder(url.Query()) // replace _ with holidays
    fe(err)

    // or add trips by json
    json := []byte(
        `[{"Start":"2022-01-01", "End":"2022-01-01"},
          {"Start":"2023-01-10", "End":"2023-02-08"},
          {"Start":"2023-02-11", "End":"2023-04-04"},
          {"Start":"2023-07-01", "End":"2023-07-30"},
          {"Start":"2024-06-10", "End":"2024-06-14"}]`,
    )
    holidays, err := HolidaysJSONDecoder(json)
    fe(err)

    // calculate
    trips, err := Calculate(holidays)
    fe(err)

    // show whether or not trips breach, the maximum compound days away,
    // and other trip details
    fmt.Printf("breach?: %t\n", trips.Breach)
    fmt.Printf("longest stay: %d\n", trips.DaysAway)
    fmt.Printf("window details: %s\n", trips.Window())
    fmt.Printf("window components: %s", trips.Holidays)

    // Output:
    // breach?: true
    // longest stay: 91
    // window details: Tuesday 10 January 2023 : Saturday 8 July 2023 (91 days, 3 overlaps)
    // window components: [
        01/01/2022 to 01/01/2022 (1 days) 10/01/2023 to 08/02/2023 (30 days) [overlap 30 days]
        11/02/2023 to 04/04/2023 (53 days) [overlap 53 days] 01/07/2023 to 30/07/2023 (30 days) [overlap 8 days]
        10/06/2024 to 14/06/2024 (5 days)
       ]
}

Documentation

Overview

Example
// package variables
WindowMaxDays = 180      // maximum window of days to calculate over
CompoundStayMaxDays = 90 // longest allowed compound trip length in days

// fail immediately on error
fe := func(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// add trips by url
url, _ := url.ParseRequestURI(
	"http://test.com/?" +
		"Start=2022-01-01&End=2022-01-01&" +
		"Start=2023-01-10&End=2023-02-08&" +
		"Start=2023-02-11&End=2023-04-04&" +
		"Start=2023-07-01&End=2023-07-30&" +
		"Start=2024-06-10&End=2024-06-14",
)
_, err := HolidaysURLDecoder(url.Query()) // replace _ with holidays
fe(err)

// or add trips by json
json := []byte(
	`[{"Start":"2022-01-01", "End":"2022-01-01"},
		  {"Start":"2023-01-10", "End":"2023-02-08"},
		  {"Start":"2023-02-11", "End":"2023-04-04"},
		  {"Start":"2023-07-01", "End":"2023-07-30"},
		  {"Start":"2024-06-10", "End":"2024-06-14"}]`,
)
holidays, err := HolidaysJSONDecoder(json)
fe(err)

// calculate
trips, err := Calculate(holidays)
fe(err)

// show whether or not trips breach, the maximum compound days away,
// and other trip details
fmt.Printf("breach?: %t\n", trips.Breach)
fmt.Printf("longest stay: %d\n", trips.DaysAway)
fmt.Printf("window details: %s\n", trips.Window)
fmt.Printf("window components: %s", trips.Holidays)
Output:

breach?: true
longest stay: 91
window details: window Tuesday 10 January 2023:Saturday 8 July 2023 overlap Tuesday 10 January 2023:Saturday 8 July 2023 (91 days, 3 overlaps)
window components: [01/01/2022 to 01/01/2022 (1 days) 10/01/2023 to 08/02/2023 (30 days) [overlap 30 days] 11/02/2023 to 04/04/2023 (53 days) [overlap 53 days] 01/07/2023 to 30/07/2023 (30 days) [overlap 8 days] 10/06/2024 to 14/06/2024 (5 days)]

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// WindowMaxDays maximum window of days to calculate over
	WindowMaxDays int = 180
	// CompoundStayMaxDays is the longest allowed compound trip length
	CompoundStayMaxDays int = 90
)

Functions

func HolidaysURLEncode added in v0.6.0

func HolidaysURLEncode(hols []Holiday) string

HolidaysURLEncode url encodes a slice of Holiday ordered by holiday rather than `net/url.Encode`'s sort by key

Types

type Holiday added in v0.5.0

type Holiday struct {
	Start          time.Time `json:"start"`                                // start date
	End            time.Time `json:"end"`                                  // end date
	Duration       int       `json:"duration,omitempty" form:",omitempty"` // duration in days
	PartialHoliday *Holiday  `json:"overlap,omitempty"`                    // pointer to a partial holiday
}

Holiday describes a trip to a EU state with Start and End date. A Holiday describes a period of with a duration of at least one day (when Start and End are the same date). A holiday End date may not be before its Start.

The Holiday struct is also used to describe partial holidays which overlap the holiday under consideration for any calculation window in Trips.calculate.

func HolidaysJSONDecoder added in v0.5.0

func HolidaysJSONDecoder(input []byte) ([]Holiday, error)

HolidaysJSONDecoder decodes a set of holidays provided as JSON

func HolidaysURLDecoder added in v0.5.0

func HolidaysURLDecoder(input url.Values) ([]Holiday, error)

HolidaysURLDecoder decodes a set of holidays provided as a URL.Query

func (Holiday) String added in v0.5.0

func (h Holiday) String() string

String returns a string representation of a holiday

type Trips

type Trips struct {
	WindowSize int       // size of window of days to search over
	MaxStay    int       // the maximum length of trips in window
	Start, End time.Time // the start and end of the overall holidays

	OriginalHolidays []Holiday // list of holidays under consideration
	Window                     // the window with the longest compound trip length
	LongestDaysAway  int       // used during window calculations
	Error            error     `json:"error"`  // calculation errors
	Breach           bool      `json:"breach"` // if CompoundStayMaxDays is breached
	// contains filtered or unexported fields
}

Trips describe a set of holidays and their calculation results.

Details following calculation are largely held in the `window` embedded struct which reports the window calculated to have longest number of days away. Where more than one window has the same number of days away, the window with the earliest date is used.

func Calculate added in v0.5.0

func Calculate(hols []Holiday) (*Trips, error)

Calculate initialises a new Trips struct with the package variables WindowSize (the number of days over which to do the calculation) and MaxStay (the length of compound holidays) and then sequentially adds holidays, then runs the calculation, returning the resulting Trips object and embedded window (with the longest DaysAway), and error if any.

func (Trips) String

func (trips Trips) String() string

String returns a simple string representation of trips

type Window added in v0.7.0

type Window struct {
	Start        time.Time `json:"start"`        // start of this window
	End          time.Time `json:"end"`          // end of this window
	DaysAway     int       `json:"daysAway"`     // days away during this window
	Overlaps     int       `json:"overlaps"`     // number of holiday overlaps
	OverlapStart time.Time `json:"overlapStart"` // start of the overlap
	OverlapEnd   time.Time `json:"overlapEnd"`   // end of the overlap
	Holidays     []Holiday `json:"holidays"`     // trips.OriginalHolidays decorated with overlaps
}

Window stores the results of a calculation window. The window with the longest compound trip length (or `DaysAway`) is copied into the Trips struct.

Start and End describe the start and end of the window (typically 180 days). While the longest overlap between the window in question and holidays is reported by OverlapStart and OverlapEnd.

Holidays are copied from Trips.OriginalHolidays to window.Holidays and decorated with partial Holidays where these overlap by the calculate function. The window with the longest DaysAway is copied to Trips.

func (Window) String added in v0.7.0

func (w Window) String() string

String returns a printable version of a window

Jump to

Keyboard shortcuts

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